Существует множество рекомендаций относительно того, когда использовать ConfigureAwait(false)
при использовании await / async в C #.
Похоже, общая рекомендация - использовать ConfigureAwait(false)
в коде библиотеки, поскольку это редко зависит от контекста синхронизации.
Однако предположим, что мы пишем очень общий служебный код, который принимает функцию в качестве входных данных. Простым примером могут быть следующие (неполные) функциональные комбинаторы, упрощающие выполнение простых операций, основанных на задачах:
Карта:
public static async Task<TResult> Map<T, TResult>(this Task<T> task, Func<T, TResult> mapping)
{
return mapping(await task);
}
FlatMap:
public static async Task<TResult> FlatMap<T, TResult>(this Task<T> task, Func<T, Task<TResult>> mapping)
{
return await mapping(await task);
}
Вопрос в том, должны ли мы использовать в этом случае ConfigureAwait(false)
? Я не уверен, как работает захват контекста. закрытия.
С одной стороны, если комбинаторы используются функционально, контекст синхронизации не требуется. С другой стороны, люди могут неправильно использовать API и делать контекстно-зависимые вещи в предоставленных функциях.
Один из вариантов - иметь отдельные методы для каждого сценария (Map
и MapWithContextCapture
или что-то в этом роде), но это выглядит некрасиво.
Другой вариант может заключаться в том, чтобы добавить параметр для отображения / плоской карты из и в ConfiguredTaskAwaitable<T>
, но поскольку ожидаемым объектам не нужно реализовывать интерфейс, это приведет к большому количеству избыточного кода и, на мой взгляд, будет еще хуже.
Есть ли хороший способ передать ответственность вызывающей стороне, чтобы реализованной библиотеке не нужно было делать никаких предположений о том, нужен ли контекст в предоставленных функциях сопоставления?
Или это просто факт, что асинхронные методы не слишком хорошо сочетаются без различных предположений?
РЕДАКТИРОВАТЬ
Просто чтобы прояснить несколько вещей:
- Проблема действительно существует. Когда вы выполняете «обратный вызов» внутри служебной функции, добавление
ConfigureAwait(false)
приведет к нулевой синхронизации. контекст. - Главный вопрос в том, как действовать в этой ситуации. Должны ли мы игнорировать тот факт, что кто-то может захотеть использовать синхронизацию. контекст, или есть хороший способ переложить ответственность на вызывающего, помимо добавления некоторой перегрузки, флага или чего-то подобного?
Как упоминается в нескольких ответах, можно было бы добавить к методу bool-flag, но, как я вижу, это тоже не слишком красиво, поскольку его придется распространять на всем протяжении API (поскольку есть больше "служебных" функций, в зависимости от показанных выше).
ConfigureAwait(false)
, все, что вам нужно было сделать, это запустить код один раз с делегатом, который распечатывает текущий контекст, или даже просто код, который выйдет из строя, если исходный контекст не был захвачен. Это заняло бы у вас гораздо меньше времени, чем написание этого вопроса, учитывая, что у вас уже написан весь код. - person Servy   schedule 04.05.2015ConfigureAwait(false)
к вашему методу к тому, что текущий контекст будет нулевым или ненулевым в обратном вызове. Если вы знаете, что оно не равно нулю, вы должны четко указать это в вопросе, который просто задаете, о том, как лучше всего справиться с этим фактом. В частности, ваш вопрос гласит:I am unsure how the context capture works wrt. closures.
Это означает, что вы не знаете, что произойдет. Если вы знаете, но не знаете, как предоставить определенный набор функций при таком поведении, значит, именно здесь вам неясно. - person Servy   schedule 04.05.2015