任务后台工作程序c#
是否有任何变化表明多个后台工作人员在5秒运行进程上的性能优于任务?我记得在一本书中读到,任务是为短时间运行的进程设计的 我问的理由是: 我有一个过程需要5秒才能完成,还有4000个过程需要完成。起初我是这样做的:任务后台工作程序c#,c#,multithreading,backgroundworker,task,C#,Multithreading,Backgroundworker,Task,是否有任何变化表明多个后台工作人员在5秒运行进程上的性能优于任务?我记得在一本书中读到,任务是为短时间运行的进程设计的 我问的理由是: 我有一个过程需要5秒才能完成,还有4000个过程需要完成。起初我是这样做的: for (int i=0; i<4000; i++) { Task.Factory.StartNewTask(action); } for(int i=0;i { bk.DoWork+=(s,e)=> { while(toDoActions.Count>0) { 行动a
for (int i=0; i<4000; i++) {
Task.Factory.StartNewTask(action);
}
for(int i=0;i
{
bk.DoWork+=(s,e)=>
{
while(toDoActions.Count>0)
{
行动a;
if(toDoActions.TryDequeue(out a))
{
a();
}
}
}
bk.RunWorkerAsync();
});
这表现得更好。即使在我有30名背景工作人员的情况下(与第一个案例中的任务数量相同),它的表现也比任务要好得多
乐:
我开始这样的任务:
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();
});
public static Task IndexFile(string file)
{
Action<object> indexAction = new Action<object>((f) =>
{
Index((string)f);
});
return Task.Factory.StartNew(indexAction, file);
}
公共静态任务索引文件(字符串文件)
{
动作索引动作=新动作((f)=>
{
索引((字符串)f);
});
返回Task.Factory.StartNew(索引操作,文件);
}
索引方法是这样的:
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.");
}
}
}
私有静态无效索引(字符串文件)
{
AudioDetectionServiceReference.AudioDetectionServiceClient=新的AudioDetectionServiceReference.AudioDetectionServiceClient();
client.IndexCompleted+=(s,e)=>
{
如果(例如错误!=null)
{
if(FileError!=null)
{
文件错误(客户端,
新的FileIndexErrorEventArgs((字符串)e.UserState,e.Error));
}
}
其他的
{
如果(文件索引!=null)
{
文件索引(客户端,新的FileIndexedEventArgs((字符串)e.UserState));
}
}
};
使用(IAudio proxy=new BassProxy())
{
列表最大值=新列表();
if(proxy.ReadFFTData(文件,out max))
{
而(最大计数>0&&max.First()==0)
{
最大移动量(0);
}
while(max.Count>0&&max.Last()==0)
{
最大移动量(最大计数-1);
}
index.sync(max.ToArray(),文件,文件);
}
其他的
{
抛出新的CouldNotIndexException(文件“音频代理未返回此文件的任何数据”);
}
}
}
此方法使用Bass.net库从mp3文件读取一些数据。然后,使用异步方法将该数据发送到WCF服务。
创建任务的IndexFile(字符串文件)方法在for循环中被调用4000次。
FileIndexed和FileError这两个事件不会被处理,因此它们永远不会被抛出。您考虑过使用threadpool吗
如果您在使用线程时性能较慢,这只能是由于线程开销(分配和销毁单个线程)。鉴于您有一个严格定义的任务列表,我会使用
并行
类(For或ForEach
,具体取决于什么更适合您)。此外,您可以将配置参数传递给这些方法中的任何一种,以控制实际同时执行的任务数:
System.Threading.Tasks.Parallel.For(0, 20000, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, i =>
{
//do something
});
上述代码将执行20000次操作,但同时执行的操作不会超过5次
我怀疑后台工作人员为您做得更好的原因是因为您在一开始就创建并实例化了他们,而在您的示例Task
code中,似乎您正在为每个操作创建一个新的Task
对象
或者,您是否考虑过使用一个固定数量的
任务
对象,在开始时实例化,然后使用ConcurrentQueue
执行类似的操作,就像您对后台工作人员所做的那样?这也应该被证明是相当有效的。任务性能如此差的原因是因为您执行了太多的小任务(4000)。请记住,CPU也需要安排任务,因此装载大量短期任务会给CPU带来额外的工作负载。更多信息见以下第二段:
从.NETFramework4开始,TPL是解决此问题的首选方法
编写多线程和并行代码。然而,并非所有代码都是可用的
适合并行化;例如,如果循环仅执行
每次迭代的工作量很小,或者没有运行很多次
迭代,那么并行化的开销会导致代码
慢点跑
使用后台工作线程时,将可能的活动线程数限制为进程计数。这减少了大量的调度开销。您可能希望使用
BlockingCollection
而不是ConcurrentQueue
(它将在内部使用ConcurrentQueue
)。这将使代码更干净、更易于使用。感谢您的提示…我将更改:)您是否尝试了并行。使用一系列操作调用?嗯…1分钟内只完成了3-4个操作?如果他们真的做到平均5秒,那么这里就有点不对劲了……太离谱了。我想了解更多关于如何开始任务的信息。@BrianGideon表示同意。我想知道任务所做的事情是否会导致它们互相攻击,或者造成并发瓶颈。(数据库死锁和排序)那么,任务是从线程池中检索的吗?我正在创建任务对象,而不是线程。