And*_*agu 6 c# multithreading task backgroundworker
多个后台工作人员在5秒运行进程中的执行效果是否优于任务?我记得在一本书中读到一个任务是为短时间运行的过程而设计的.
我要问的是:
我有一个需要5秒钟才能完成的过程,并且有4000个过程需要完成.起初我做了:
for (int i=0; i<4000; i++) {
Task.Factory.StartNewTask(action);
}
Run Code Online (Sandbox Code Playgroud)
并且性能很差(在第一分钟之后,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();
});
Run Code Online (Sandbox Code Playgroud)
这样做的方式更好.即使我有30名背景工作人员(与第一种情况一样多的任务),它的表现要比任务好得多.
LE:
我像这样启动任务:
public static Task IndexFile(string file)
{
Action<object> indexAction = new Action<object>((f) =>
{
Index((string)f);
});
return Task.Factory.StartNew(indexAction, file);
}
Run Code Online (Sandbox Code Playgroud)
而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.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个方法使用Bass.net库从mp3文件中读取一些数据.然后使用异步方法将该数据发送到WCF服务.创建任务的IndexFile(字符串文件)方法在for循环中调用4000次.不处理这两个事件,FileIndexed和FileError,因此永远不会抛出它们.
任务性能如此差的原因是因为您挂载了太多小任务(4000)。请记住,CPU 也需要调度任务,因此安装大量短期任务会给 CPU 带来额外的工作负载。更多信息可以在TPL第二段中找到:
从 .NET Framework 4 开始,TPL 是编写多线程和并行代码的首选方式。然而,并非所有代码都适合并行化;例如,如果循环在每次迭代中仅执行少量工作,或者不运行多次迭代,则并行化的开销可能会导致代码运行速度更慢。
当您使用后台工作程序时,您将可能的活动线程数限制为ProcessCount。这减少了大量的调度开销。