Ern*_*ren 4 c# multithreading asynchronous task async-await
我有一个异步方法
private async Task DoSomething(CancellationToken token)
Run Code Online (Sandbox Code Playgroud)
任务列表
private List<Task> workers = new List<Task>();
Run Code Online (Sandbox Code Playgroud)
我必须创建运行该方法的N个线程
public void CreateThreads(int n)
{
tokenSource = new CancellationTokenSource();
token = tokenSource.Token;
for (int i = 0; i < n; i++)
{
workers.Add(DoSomething(token));
}
}
Run Code Online (Sandbox Code Playgroud)
但问题是那些必须在给定时间运行
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但实际上它们在我调用CreateThreads方法(在StartAllWorkers之前)时运行.我搜索了像我这样的关键字和问题,但找不到任何关于阻止任务运行的信息.我已经尝试了很多不同的方法,但任何可以完全解决我的问题的方法.例如,将代码移动DoSomething
到a 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));
}
}
Run Code Online (Sandbox Code Playgroud)
然后,当您准备好开始任务时,只需完成"开始"信号任务:
public Task StartAllWorkers()
{
_tcs.TrySetCompleted(null);
return Task.WhenAll(workers);
}
Run Code Online (Sandbox Code Playgroud)
(StartAllWorkers
上面的方法与原始方法的语义略有不同:一旦第一个任务被取消,你的原始方法就会抛出一个取消异常;这个方法将等到所有方法完成然后抛出一个取消异常)
然后你DoSomething
只需要尊重"开始信号":
private static async Task DoSomething(Task start, CancellationToken token)
{
await start;
... // rest of your code
}
Run Code Online (Sandbox Code Playgroud)