C# 将循环转换为任务
我有以下同步代码:C# 将循环转换为任务,c#,asynchronous,async-await,task-parallel-library,c#-5.0,C#,Asynchronous,Async Await,Task Parallel Library,C# 5.0,我有以下同步代码: foreach ( var step in result ) { step.Run(); } 我试图将其转换为任务,但失败了。我尝试使用Task转换它。当所有的都是这样时(我确实在方法签名中附加了async): 这会永远阻塞。但是,当我在循环中创建一个 foreach ( var step in result ) { var t = Task.Run( () => step.Run() ); t.Wait(); } 如果改用wait Task.R
foreach ( var step in result ) {
step.Run();
}
我试图将其转换为任务,但失败了。我尝试使用Task转换它。当所有的都是这样时(我确实在方法签名中附加了async):
这会永远阻塞。但是,当我在循环中创建一个
foreach ( var step in result ) {
var t = Task.Run( () => step.Run() );
t.Wait();
}
如果改用wait Task.Run(()=>step.Run())代码>它只等待第一个线程并恢复主线程
run方法如下所示:
public async void Run() {
var result = Work();
if ( null != result && result.Count > 0 ) {
var tasks = new List<Task>();
foreach ( var step in result ) {
await Task.Run( () => step.Run() );
}
}
}
class NoWorkStep : WorkerStep {
protected override IList<WorkerStep> Work() {
Console.WriteLine( "HERE" );
List<WorkerStep> newList = new List<WorkerStep>();
for ( int i = 0; i < 10; i++ ) {
newList.Add( new NoWorkStep2() );
}
return newList;
}
}
class NoWorkStep2 : WorkerStep {
protected override IList<WorkerStep> Work() {
Console.WriteLine( "HERE-2" );
return new List<WorkerStep>();
}
}
让我们找出代码中的问题:
new Task(() => step.Run())
这将返回一个冷的任务
,意味着任务
实际上没有启动。为了启动,您需要呼叫:
new Task(() => step.Run()).Start)
但是,您不应该使用newtask
,无论如何,您应该使用Task.Run
如果改用wait Task.Run(()=>step.Run());它只在等待
第一个,然后继续主线程
这是因为Run
是async void
,不能等待async void
仅在顶级事件处理程序中使用,这里显然不是这样
如果要等待所有任务完成,可以执行以下操作:
public async Task RunAsync()
{
var result = Work();
var stepTasks = result.Select(step => Task.Run(() => step.Run()));
await Task.WhenAll(steps);
}
这将保证所有任务在RunAsync
完成后都已完成执行。您似乎没有启动任务
尝试:
var tasks=newlist();
foreach(var步进结果)
{
var t=新任务(()=>step.Run());
t、 Start();
任务。添加(t);
}
任务。WhenAll(任务);
您可以使用Parallel.ForEach
Parallel.ForEach(result, step => step.Run());
通过这种方式,您甚至不需要处理并行框架的较低级别部分 只要调用Task.Run,就不需要创建冷任务,只需在下一行中启动它。我只是想说明问题中的代码不起作用的原因。冷任务是原始代码的真正问题。很容易忘记启动调用,它们在“Task.Run”或“Task.Factory.StartNew”上不提供任何内容。我将async void Run
更改为async Task RunAsync()
,并使用了您的代码片段。我使用wait step.RunAsync()调用RunAsync不幸的是,有时它在这里打印十次-2,有时打印两次,有时不在这里-2。@Sascha谁调用doIt
?怎么做?我从static void Main
调用doIt
,那么,Main
将在doIt
有机会完成之前终止。如果在控制台应用程序中运行,则还需要使doIt
返回任务
,并使用doIt().Wait()
。谢谢。现在工作。你是对的,我一看到你的评论就明白了。谢谢你的帮助,这会起作用,也许我会以此结束,但是aync等待模式也应该起作用,我想知道我的错误在哪里。或者确实是result.AsParallel().ForAll(step=>step.Run())代码>,但除非您有实际的查询,否则您不会真正使用PLINQ。@NathanCooper您是对的,这取决于结果的类型是否合理。两者都可以,但我喜欢这里的ForEach()
,因为它保留了初始代码片段的意图。不要使用newtask
。第四个示例之所以有效,并不是因为等待
在周期内,而是因为您正在使用任务。运行而不是新任务
。
new Task(() => step.Run()).Start)
public async Task RunAsync()
{
var result = Work();
var stepTasks = result.Select(step => Task.Run(() => step.Run()));
await Task.WhenAll(steps);
}
var tasks = new List<Task>();
foreach (var step in result)
{
var t = new Task(() => step.Run());
t.Start();
tasks.Add(t);
}
Task.WhenAll(tasks);
Parallel.ForEach(result, step => step.Run());