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

时间:2021-08-21 02:21:22

I'm trying to use Task.WaitAll on a list of tasks. The thing is the tasks are an async lambda which breaks Tasks.WaitAll as it never waits.

我正在尝试在任务列表中使用Task.WaitAll。事情是任务是一个异步lambda,它打破Tasks.WaitAll,因为它永远不会等待。

Here is an example code block:

这是一个示例代码块:

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  

This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?

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

4 个解决方案

#1


15  

Task.Factory.StartNew doesn't recognise async delegates as there is no overload that accepts a function returning a Task.

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

This plus other reasons (see StartNew is dangerous) is why you should be using Task.Run here:

这加上其他原因(参见StartNew是危险的)是你应该在这里使用Task.Run的原因:

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

#2


14  

This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?

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

The reason Task.WaitAll doesn't wait for the completion of the IO work presented by your async lambda is because Task.Factory.StartNew actually returns a Task<Task>. Since your list is a List<Task> (and Task<T> derives from Task), you wait on the outer task started by StartNew, while ignoring the inner one created by the async lambda. This is why they say Task.Factory.StartNew is dangerous with respect to async.

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

How could you fix this? You could explicitly call Task<Task>.Unwrap() in order to get the inner 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());

Or like others said, you could call Task.Run instead:

或者像其他人说的那样,你可以调用Task.Run:

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

Also, since you want to be doing things right, you'll want to use Task.WhenAll, why is asynchronously waitable, instead of Task.WaitAll which synchronously blocks:

此外,既然你想做正确的事情,你会想要使用Task.WhenAll,为什么是异步等待,而不是同步阻止的Task.WaitAll:

await Task.WhenAll(tasks);

#3


0  

You can do like this.

你可以这样做。

    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...
        }
    }

#4


-1  

you have to use the Task.ContinueWith method. Like this

你必须使用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...
            });
        }
    }
}

#1


15  

Task.Factory.StartNew doesn't recognise async delegates as there is no overload that accepts a function returning a Task.

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

This plus other reasons (see StartNew is dangerous) is why you should be using Task.Run here:

这加上其他原因(参见StartNew是危险的)是你应该在这里使用Task.Run的原因:

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

#2


14  

This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?

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

The reason Task.WaitAll doesn't wait for the completion of the IO work presented by your async lambda is because Task.Factory.StartNew actually returns a Task<Task>. Since your list is a List<Task> (and Task<T> derives from Task), you wait on the outer task started by StartNew, while ignoring the inner one created by the async lambda. This is why they say Task.Factory.StartNew is dangerous with respect to async.

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

How could you fix this? You could explicitly call Task<Task>.Unwrap() in order to get the inner 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());

Or like others said, you could call Task.Run instead:

或者像其他人说的那样,你可以调用Task.Run:

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

Also, since you want to be doing things right, you'll want to use Task.WhenAll, why is asynchronously waitable, instead of Task.WaitAll which synchronously blocks:

此外,既然你想做正确的事情,你会想要使用Task.WhenAll,为什么是异步等待,而不是同步阻止的Task.WaitAll:

await Task.WhenAll(tasks);

#3


0  

You can do like this.

你可以这样做。

    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...
        }
    }

#4


-1  

you have to use the Task.ContinueWith method. Like this

你必须使用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...
            });
        }
    }
}