控制线程数(而不是任务)
本文关键字:任务 控制线 线程 控制 | 更新日期: 2023-09-27 18:25:57
我有一个文件列表,我需要运行的每个文件(PCAP文件-传输数据包)都有自己的运行时间。
因为我想要处理多个文件并行的选项,所以我使用这个函数来获得IEnumerable<string> source
和最大并行线程数:
public void doWork(IEnumerable<string> _source, int parallelThreads)
{
_tokenSource = new CancellationTokenSource();
var token = _tokenSource.Token;
Task.Factory.StartNew(() =>
{
try
{
Parallel.ForEach(_source,
new ParallelOptions
{
MaxDegreeOfParallelism = parallelThreads //limit number of parallel threads
},
file =>
{
if (token.IsCancellationRequested)
return;
//process my file...
});
}
catch (Exception)
{ }
}, _tokenSource.Token).ContinueWith(
t =>
{
//finish all the list...
}
, TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
);
}
例如,如果我有10个文件的列表,并且我的最大并行线程数是4,所以我的程序开始并行传输4个文件,在第一个文件完成后,另一个1个文件自动启动,如果我传输所有列表1次,这就可以了。
在添加了在循环中播放所有列表的选项后,我遇到了一个问题,例如,如果我想播放两次所有列表,在第一个循环结束后,第二个循环开始,并且在第一个文件完成后,在这个循环中,所有UI都被卡住,没有响应。我和一个朋友聊过,他是C#开发人员,他告诉我这可能是任务已知的问题,有时会陷入僵局。可以用另一个类代替Task吗?
文件IO不应该使用Parallel.ForEach
。这不是一项cpu密集型任务。你应该能够一个接一个地开始所有的任务。这样,您将使用更少的线程,并且您的应用程序将更具可扩展性。
更新示例:
public static void doWork(IEnumerable<string> _source, int numThreads)
{
var _tokenSource = new CancellationTokenSource();
List<Task> tasksToProcess = new List<Task>();
foreach (var file in _source)
{
tasksToProcess.Add( Task.Factory.StartNew(() =>
{
Console.WriteLine("Processing " + file );
//do file operation
Thread.Sleep(5000);
Console.WriteLine("Finished Processing " + file);
},
_tokenSource.Token));
if(tasksToProcess.Count % numThreads == 0)
{
Console.WriteLine("Waiting for tasks");
Task.WaitAll(tasksToProcess.ToArray(), _tokenSource.Token);
Console.WriteLine("All tasks finished");
tasksToProcess.Clear();
}
}
}
void Main()
{
var fileList = Enumerable.Range(0, 100).Select (e => "file" + e.ToString());
doWork(fileList, 4);
Console.ReadLine();
}