创建一个任务列表,其中包含不执行的任务
本文关键字:任务 包含不 执行 列表 一个 创建 | 更新日期: 2023-09-27 18:37:04
我有一个异步方法
private async Task DoSomething(CancellationToken token)
任务列表
private List<Task> workers = new List<Task>();
我必须创建运行该方法的 N 个线程
public void CreateThreads(int n)
{
tokenSource = new CancellationTokenSource();
token = tokenSource.Token;
for (int i = 0; i < n; i++)
{
workers.Add(DoSomething(token));
}
}
但问题是这些必须在给定时间运行
public async Task StartAllWorkers()
{
if (workers.Count > 0)
{
try
{
while (workers.Count > 0)
{
Task finishedWorker = await Task.WhenAny(workers.ToArray());
workers.Remove(finishedWorker);
finishedWorker.Dispose();
}
if (workers.Count == 0)
{
tokenSource = null;
}
}
catch (OperationCanceledException)
{
throw;
}
}
}
但实际上,当我调用 CreateThreads 方法(在 StartAllWorkers 之前)时,它们会运行。我搜索了像我这样的关键字和问题,但找不到有关停止任务运行的任何内容。我尝试了很多不同的方法,但任何可以完全解决我的问题的方法。例如,将代码从DoSomething
移动到workers.Add(new Task(async () => { }, token));
将运行StartAllWorkers()
,但线程永远不会真正启动。
还有另一种调用tokenSource.Cancel()
的方法。
您可以将TaskCompletionSource<T>
用作异步方法的一次性"信号"。
所以你会像这样创建它:
private TaskCompletionSource<object> _tcs;
public void CreateThreads(int n)
{
_tcs = new TaskCompletionSource<object>();
tokenSource = new CancellationTokenSource();
token = tokenSource.Token;
for (int i = 0; i < n; i++)
{
workers.Add(DoSomething(_tcs.Task, token));
}
}
然后,当您准备好启动任务时,只需完成"开始"信号任务:
public Task StartAllWorkers()
{
_tcs.TrySetCompleted(null);
return Task.WhenAll(workers);
}
(上面的StartAllWorkers
方法的语义与原始方法略有不同:您的原始方法会在第一个任务取消后立即抛出取消异常;这个方法将等到所有方法完成,然后抛出取消异常)
然后,您的DoSomething
只需要遵守"开始信号":
private static async Task DoSomething(Task start, CancellationToken token)
{
await start;
... // rest of your code
}
这个想法怎么样:
保存任务引用项列表,而不是保存任务列表:
public class TaskReference
{
private readonly Func<Task> _func;
public TaskReference(Func<Task> func)
{
_func = func;
}
public async Task RunAsync()
{
await _func();
}
}
添加到列表的工作方式如下:
taskList.Add(new TaskReference(() => DoSomething(myToken)));
并像这样执行:
await Task.WhenAll(taskList.Select(o => o.RunAsync()));