it-swarm.com.ru

Task.Factory.StartNew с асинхронной лямбдой и Task.WaitAll

Я пытаюсь использовать Task.WaitAll в списке задач. Дело в том, что задачи - это асинхронная лямбда, которая ломает 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  

Это не ждет из-за асинхронной лямбды. Так как же мне ожидать операций ввода-вывода в моей лямбде?

14
Jacob Roberts

Task.Factory.StartNew не распознает делегатов async, поскольку нет перегрузки, которая принимает функцию, возвращающую Task

Это плюс другие причины (см. StartNew опасен ), поэтому вы должны использовать Task.Run здесь:

tasks.Add(Task.Run(async () => ...
16
Charles Mager

Это не ждет из-за асинхронной лямбды. Так как я должен жду операций ввода/вывода в моей лямбде?

Причина, по которой Task.WaitAll не ожидает завершения работы IO, представленной асинхронной лямбдой, заключается в том, что Task.Factory.StartNew фактически возвращает Task<Task>. Поскольку ваш список представляет собой List<Task>Task<T> происходит от Task), вы ожидаете внешнюю задачу, запущенную StartNew, в то время как игнорируете внутреннюю задачу , созданную асинхронной лямбдой. Вот почему они говорят, что 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);
18
Yuval Itzchakov

Вы можете сделать это так.

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