为什么async在没有被告知的情况下等待
本文关键字:情况下 等待 被告 async 为什么 | 更新日期: 2023-09-27 17:51:11
我正试图让我的系统的一部分并行运行,但出于某种原因,它会在启动下一个元素之前等待每个元素,尽管我没有告诉它等待。我想开始为每个this.Items
执行ExecuteItem
,然后在它们全部完成后继续。
bool singleThread = false;
public async Task Execute()
{
if (!this.singleThread)
{
var tasks = this.Items.Select(x => this.ExecuteItem(x)).ToArray();
Task.WaitAll(tasks);
}
else
{
foreach (var item in this.Items)
{
await this.ExecuteItem(item);
}
}
}
private async Task ExecuteItem(IMyItem item)
{
MappedDiagnosticsContext.Set("itemRef", item.ItemRef);
try
{
await this.HandelItem(item);
}
catch (Exception exp)
{
Logger.ErrorException(string.Format("Execution for {0} failed.", item.ItemName), exp);
Logger.Error("Error Message: ", exp.Message);
}
MappedDiagnosticsContext.Remove("itemRef");
}
为了弄清楚我的问题,我的代码表现得好像写了下面的
var tasks = this.Items.Select(x => await this.ExecuteItem(x)).ToArray();
为了确保这不是某种linq问题,我将问题代码改写为以下代码,但代码仍然阻止tasks[i] = this.ExecuteItem(this.Items[i]);
Task[] tasks = new Task[this.Items.Count];
for (int i = 0; i < this.Items.Count; i++)
{
Console.WriteLine("Adding " + this.Items[i].ItemName);
tasks[i] = this.ExecuteItem(this.Items[i]);
}
Console.WriteLine("Waiting!!!");
Task.WaitAll(tasks);
HandelItem
中有东西正在阻塞。
async
方法不是完全异步运行的,它们是同步执行的,直到达到await
为止。因此,在建立tasks
列表之前,将运行所有ExecuteItem
,直到HandelItem
。如果是async
方法,则这种同步行为将持续到HandelItem
,因此HandelItem
很可能是在构建任务列表时执行的。
这一点在以下示例程序中很容易看出:
static void Main(string[] args)
{
var items = Enumerable.Range(1, 2);
Console.WriteLine("Start");
var tasks = items.Select(i => AsyncMethod(i)).ToArray();
Console.WriteLine("Got tasks");
Task.WaitAll(tasks);
Console.WriteLine("Done!");
}
static async Task AsyncMethod(int i)
{
Console.WriteLine("Enter {0}", i);
await AsyncMethod2(i);
await Task.Delay(1000);
Console.WriteLine("Exit {0}", i);
}
static async Task AsyncMethod2(int i)
{
Console.WriteLine("Enter2 {0}", i);
await Task.Delay(2000);
Console.WriteLine("Exit2 {0}", i);
}
其输出为:
Start
Enter 1
Enter2 1
Enter 2
Enter2 2
Got tasks
Exit2 2
Exit2 1
Exit 1
Exit 2
Done!
因此,两个async
方法都在构建任务列表时运行,直到它们必须等待为止。因此,如果HandelItem
做了一些非异步的事情,就会导致阻塞。
如果您希望任务并行执行;并等待,直到全部完成:
await Task.WhenAll(this.Items.Select(item=>this.ExecuteItem(item)));