C# “返回”;等待任务<;字符串>;。运行(……)”;有时悬挂
这是我的代码的复制,其中C# “返回”;等待任务<;字符串>;。运行(……)”;有时悬挂,c#,async-await,parallel.foreach,C#,Async Await,Parallel.foreach,这是我的代码的复制,其中等待Task.Run(..)中的返回有时会挂起。如果失败,主要是第一次呼叫 我怎样才能改进它 using System.Threading.Tasks; using System.Diagnostics; private void Button_Click(object sender, RoutedEventArgs e) { // This can be a very huge list string[] servers = new string[]
等待Task.Run(..)
中的返回有时会挂起。如果失败,主要是第一次呼叫
我怎样才能改进它
using System.Threading.Tasks;
using System.Diagnostics;
private void Button_Click(object sender, RoutedEventArgs e)
{
// This can be a very huge list
string[] servers = new string[] { "10.17.100.1", "10.17.100.10", "10.17.100.20" };
// the max parallel tasks must be limited
Parallel.ForEach(servers,
new ParallelOptions { MaxDegreeOfParallelism = 10 },
(forServer) =>
{
this.Method1Async(forServer).Wait();
});
Debug.WriteLine("Finished");
}
private async Task Method1Async(string server)
{
await this.Method2Async(server);
}
private async Task Method2Async(string server)
{
Debug.WriteLine("> Method2Async");
string result = await Task<string>.Run(() =>
{
Debug.WriteLine(" Method2Async before return");
return GetDataFromServer(server);
});
Debug.WriteLine("< Method2Async");
}
private string GetDataFromServer(string server)
{
// any long time running stuff
Thread.Sleep(10000);
return "the server data";
}
注:感谢Theodor Zoulias提到这一点: 根据
Parallel.ForEach
不会等待任务完成,因此wait
ing在操作中不会做任何事情,并且IsCompleted
将在所有任务启动后立即设置为true
将
ForEach
操作的签名更改为async
,以启用wait
ing
using System.Threading.Tasks;
using System.Diagnostics;
private void Button_Click(object sender, RoutedEventArgs e)
{
string[] dummyArray = new string[] { "anyvalue" };
Parallel.ForEach(dummyArray, async (forDummy) =>
{
await this.Method1Async();
});
Debug.WriteLine("Finished");
}
private async Task Method1Async()
{
await this.Method2Async();
}
private async Task Method2Async()
{
Debug.WriteLine("> Method2Async");
string result = await Task<string>.Run(() =>
{
Debug.WriteLine(" Method2Async before return");
return "anydata"; // this return sometimes does not "come back" ...
});
// ... so this code is never reached
Debug.WriteLine("< Method2Async" + result);
}
或
编辑:
如果要限制并行任务的数量,可以执行以下操作:
另一种选择是使用显然非常流行的
wait
ableforeach
构造可以通过迭代任何IEnumerable
或IAsyncnumerable来实现。
using Dasync.Collections;
string[] servers = new string[] { "10.17.100.1", "10.17.100.10", "10.17.100.20" };
await servers.ParallelForEachAsync<string>(async forServer =>
{
await this.Method1Async(forServer);
}, maxDegreeOfParallelism: 10);
不要在任务上使用
.Wait()
。什么叫“等待并行.ForEach的完成”?这是一个同步调用,直到所有并行任务完成后才会返回。IIRC,await告诉编译器和运行时“重新洗牌,使函数的其余部分成为回调”。Wait()只是一个函数调用。等待等于或略高于括号。很容易让他们混淆。请更新您的问题,没有anydata
,您可能会发现这很有趣:。问题中还有一个嵌套的Parallel.ForEach
,看起来像是抄本错误。@marsh wiggle您可以改为,创建一个循环并检查ParallelLoopResult.IsCompleted,但对于本例来说,这是一个过分的做法。@marsh wiggle,您在想要的输出中说过,您希望在第一个循环完成后调用第二个循环。对吗?@marsh wiggle我添加了另一个更新。我希望它有助于并行.ForEach
。通过的lambda是@marsh wiggle请再次查看更新的答案和上面的评论。似乎平行foreach有一个局限性。
using System.Threading.Tasks;
using System.Diagnostics;
private void Button_Click(object sender, RoutedEventArgs e)
{
string[] dummyArray = new string[] { "anyvalue" };
Parallel.ForEach(dummyArray, async (forDummy) =>
{
await this.Method1Async();
});
Debug.WriteLine("Finished");
}
private async Task Method1Async()
{
await this.Method2Async();
}
private async Task Method2Async()
{
Debug.WriteLine("> Method2Async");
string result = await Task<string>.Run(() =>
{
Debug.WriteLine(" Method2Async before return");
return "anydata"; // this return sometimes does not "come back" ...
});
// ... so this code is never reached
Debug.WriteLine("< Method2Async" + result);
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
string[] dummyArray = new string[] { "anyvalue" };
Task[] tasks = dummyArray.Select(async x => await Method1Async()).ToArray();
await Task.WhenAll(tasks);
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
string[] dummyArray = new string[] { "anyvalue" };
Task[] tasks = dummyArray.Select(x => Method1Async()).ToArray();
await Task.WhenAll(tasks);
}
public async Task Button_Click()
{
string[] servers = new string[] { "1", "2", "3", "4", "5" };
var maxParallel = 3;
var throttler = new SemaphoreSlim(initialCount: maxParallel);
var tasks = servers.Select(async server =>
{
try
{
await throttler.WaitAsync();
await Method1Async(server);
}
finally
{
throttler.Release();
}
});
await Task.WhenAll(tasks);
Console.WriteLine("Finished");
}
using Dasync.Collections;
string[] servers = new string[] { "10.17.100.1", "10.17.100.10", "10.17.100.20" };
await servers.ParallelForEachAsync<string>(async forServer =>
{
await this.Method1Async(forServer);
}, maxDegreeOfParallelism: 10);
using Dasync.Collections;
string[] servers = new string[] { "10.17.100.1", "10.17.100.10", "10.17.100.20" };
ConcurrentBag<string> bag = new ConcurrentBag<string>();
await severs.ParallelForEachAsync<string>(async forServer =>
{
string response = await this.Method1Async(forServer);
bag.Add(response);
}, maxDegreeOfParallelism: 10);
foreach(string forBagItem in bag)
{
// evaluate the results
}