Необходимо ли обернуть продолжение, которое будет в потоке без графического интерфейса, с помощью Task.Run? - PullRequest
1 голос
/ 14 мая 2019

Этот вопрос предназначен для учебных целей.Я точно не занимаюсь разработкой.

У меня есть две длительные операции с привязкой к процессору (JobA и JobB).Оба не взаимодействуют с GUI.В отличие от Task.FromResult, который завершается немедленно в выражении await, my Task.Run(()=>JobA()).ConfigureAwait(false) возвращает управление вызывающей стороне и вызывает выполнение продолжения в потоке без GUI (из-за ConfigureAwait(false)).

static void  JobA()
{
    for (int i = 0; i < int.MaxValue; i++) ;
}

static void JobB()
{
    for (int i = 0; i < int.MaxValue; i++) ;
}


private static async Task Async()
{            
    await Task.Run(()=>JobA()).ConfigureAwait(false);
    JobB();
    //await Task.Run(() => JobB());
}

private async void Button_Click(object sender, RoutedEventArgs e)
{  
    await Async();
}

Вопрос

В моем понимании, перенос JobB с Task.Run, как во втором случае ниже, не является необходимым, потому что продолжение уже гарантированно будет работать в потоке без GUI.

private static async Task Async()
{            
    await Task.Run(()=>JobA()).ConfigureAwait(false);
    JobB();
}

private static async Task Async()
{            
    await Task.Run(()=>JobA()).ConfigureAwait(false);
    await Task.Run(() => JobB());
}

Exception поведение в асинхронном режиме немного сложнее, поэтому я задаю этот вопрос, потому что я хочу знать, рискованно ли исключение при возникновении исключения.Если такого риска нет, я удалю этот вопрос.

1 Ответ

5 голосов
/ 14 мая 2019

my Task.Run (() => JobA ()). ConfigureAwait (false) возвращает управление вызывающей стороне и вызывает выполнение продолжения в потоке без GUI (из-за ConfigureAwait (false))

В самом деле? Вы уверены?

Один интересный аспект await заключается в том, что он ведет себя синхронно, если это возможно. Таким образом, если задание уже выполнено к моменту, когда await проверит его, await продолжит работать синхронно. В этом случае ConfigureAwait не имеет никакого эффекта.

В частности, это может произойти, когда у вас разные компьютеры с разными скоростями процессора, или доступной памятью, или поведением кеша. Получив дозу Закона Мерфи, вы столкнетесь с производственной проблемой, которую не сможете воспроизвести, что всегда весело.

Итак, я никогда не полагаюсь на ConfigureAwait(false), чтобы гарантировать, что любой код выполняется в потоке пула потоков. Вот для чего Task.Run. Для простого случая, который вы опубликовали, вы можете выполнять одну работу за другой в Task.Run: await Task.Run(() => { JobA(); JobB(); });

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...