Task.Factory.StartNew with async lambda and Task.WaitAll

本文关键字:Task and WaitAll lambda with Factory StartNew async | 更新日期: 2023-09-27 17:56:05

我正在尝试在任务列表中使用Task.WaitAll。 问题是任务是一个异步 lambda,它会破坏Tasks.WaitAll因为它从不等待。

下面是一个示例代码块:

List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(async () =>
{
    using (dbContext = new DatabaseContext())
    {
        var records = await dbContext.Where(r => r.Id = 100).ToListAsync();
        //do long cpu process here...
    }
}
Task.WaitAll(tasks);
//do more stuff here  

这不会因为异步 lambda 而等待。 那么,我应该如何等待 lambda 中的 I/O 操作呢?

Task.Factory.StartNew with async lambda and Task.WaitAll

>Task.Factory.StartNew无法识别async委托,因为没有重载接受返回Task的函数。

再加上其他原因(请参阅StartNew是危险的)是您应该在此处使用Task.Run的原因:

tasks.Add(Task.Run(async () => ...

这不会因为异步 lambda 而等待。那我应该怎么做 等待我的 lambda 中的 I/O 操作?

Task.WaitAll 不等待异步 lambda 提供的 IO 工作完成的原因是Task.Factory.StartNew实际上返回了一个Task<Task>。由于您的列表是一个List<Task>(并且Task<T>派生自Task),因此您等待由StartNew启动的外部任务,而忽略由异步lambda创建的内部任务。这就是为什么他们说Task.Factory.StartNew异步是危险的

你怎么能解决这个问题?您可以显式调用Task<Task>.Unwrap()以获取内部任务:

List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(async () =>
{
    using (dbContext = new DatabaseContext())
    {
        var records = await dbContext.Where(r => r.Id = 100).ToListAsync();
        //do long cpu process here...
    }
}).Unwrap());

或者像其他人说的那样,你可以打电话给Task.Run

tasks.Add(Task.Run(async () => /* lambda */);

另外,由于你想把事情做好,你会想要使用 Task.WhenAll ,为什么异步等待,而不是同步阻塞的Task.WaitAll

await Task.WhenAll(tasks);
你可以

这样做。

    void Something()
    {
        List<Task> tasks = new List<Task>();
        tasks.Add(ReadAsync());
        Task.WaitAll(tasks.ToArray());
    }
    async Task ReadAsync() {
        using (dbContext = new DatabaseContext())
        {
            var records = await dbContext.Where(r => r.Id = 100).ToListAsync();
            //do long cpu process here...
        }
    }

你必须使用Task.ContinueWith方法。喜欢这个

List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(() =>
{
    using (dbContext = new DatabaseContext())
    {
        return dbContext.Where(r => r.Id = 100).ToListAsync().ContinueWith(t =>
            {
                var records = t.Result;
                // do long cpu process here...
            });
        }
    }
}