Почему Thread.Sleep работает, а Task.Delay - нет? - PullRequest
0 голосов
/ 29 января 2020

В моем коде я предполагаю, что outerFlag будет попадать после innerFlag, но на самом деле он работает как огонь и забывает (innerFlag удаляется после outerFlag). Когда я использую Thread.Sleep вместо Task.Delay флаги бьют в правильном порядке.

Вот код:

[Test]
public async Task Test() {

    bool innerFlag = false;
    bool outerFlag = false;

    await Lock(async () => {
        await Task.Delay(2000);
        innerFlag = true;
    });

    outerFlag = true;

    Thread.Sleep(1000);
    Thread.Sleep(2500);
}

private Task Lock(Action action) {
    return Task.Run(action);
}

Я также заметил, что когда я звоню Task.Delay и устанавливаю innerFlag без Lock метода, но с помощью прямой лямбды, он работает как положено.

Может кто-нибудь объяснить такое поведение?

1 Ответ

1 голос
/ 30 января 2020

Ваш метод Lock не понимает асин c делегатов, поэтому делегат асин c, который вы пытаетесь передать в качестве аргумента, обрабатывается как async void. Асин c пустоты проблематичны c во всех отношениях, и следует избегать , если только они не используются по назначению в качестве обработчиков событий.

Чтобы гарантировать, что ваш метод понимать asyn c делегатов, вы должны создать перегрузку, которая принимает Func<Task> в качестве аргумента:

private Task Lock(Func<Task> func)
{
    return Task.Run(func);
}

Обратите внимание, что аргумент func может быть передан непосредственно Task.Run потому что этот метод также понимает asyn c делегатов. Не все встроенные методы понимают asyn c делегаты, с примечательными примерами Task.Factory.StartNew и Parallel.ForEach. Вы должны быть осторожны при каждом добавлении модификатора async в делегат. Вы должны быть уверены, что вызываемый метод распознает asyn c делегатов, иначе вы можете получить asyn c пустоты и havo c, которые они создают.

...