多个后台工作人员在 5 秒运行的进程上执行比任务更好的任何变化吗?我记得在一本书中读到任务是为短期运行的进程设计的。
我问的原因是这样的:
我有一个流程需要 5 秒才能完成,有 4000 个流程要完成。起初我是这样做的:
for (int i=0; i<4000; i++) {
Task.Factory.StartNewTask(action);
}
这性能很差(第一分钟后,完成了 3-4 个任务,控制台应用程序有 35 个线程)。也许这很愚蠢,但我认为线程池会处理这种情况(它将所有动作放在一个队列中,当一个线程空闲时,它会采取一个动作并执行它)。
现在的第二步是手动执行 Environment.ProcessorCount 后台工作人员,并将所有操作放在 ConcurentQueue 中。所以代码看起来像这样:
var workers = new List<BackgroundWorker>();
//initialize workers
workers.ForEach((bk) =>
{
bk.DoWork += (s, e) =>
{
while (toDoActions.Count > 0)
{
Action a;
if (toDoActions.TryDequeue(out a))
{
a();
}
}
}
bk.RunWorkerAsync();
});
这表现得更好。即使我有 30 个后台工作人员(与第一种情况一样多的任务),它的性能也比任务好得多。
乐:
我像这样开始任务:
public static Task IndexFile(string file)
{
Action<object> indexAction = new Action<object>((f) =>
{
Index((string)f);
});
return Task.Factory.StartNew(indexAction, file);
}
Index 方法是这样的:
private static void Index(string file)
{
AudioDetectionServiceReference.AudioDetectionServiceClient client = new AudioDetectionServiceReference.AudioDetectionServiceClient();
client.IndexCompleted += (s, e) =>
{
if (e.Error != null)
{
if (FileError != null)
{
FileError(client,
new FileIndexErrorEventArgs((string)e.UserState, e.Error));
}
}
else
{
if (FileIndexed != null)
{
FileIndexed(client, new FileIndexedEventArgs((string)e.UserState));
}
}
};
using (IAudio proxy = new BassProxy())
{
List<int> max = new List<int>();
if (proxy.ReadFFTData(file, out max))
{
while (max.Count > 0 && max.First() == 0)
{
max.RemoveAt(0);
}
while (max.Count > 0 && max.Last() == 0)
{
max.RemoveAt(max.Count - 1);
}
client.IndexAsync(max.ToArray(), file, file);
}
else
{
throw new CouldNotIndexException(file, "The audio proxy did not return any data for this file.");
}
}
}
此方法使用 Bass.net 库从 mp3 文件中读取一些数据。然后使用异步方法将该数据发送到 WCF 服务。创建任务的 IndexFile(string file) 方法在 for 循环中被调用了 4000 次。这两个事件 FileIndexed 和 FileError 没有被处理,所以它们永远不会被抛出。