Всегда ли ConfigureAwait (true) возвращается в исходный поток, даже если метод вызываемого объекта выполняет ConfigureAwait (false) внутри? - PullRequest
0 голосов
/ 31 мая 2018

Я ожидал вернуться к теме № 1 в местоположении 1.2, но не сделал этого.Есть ли способ вернуться к потоку пользовательского интерфейса после выполнения асинхронного вызова?Спасибо

Также я не могу сделать метод верхнего уровня асинхронным.Не уверен, что Async полностью решит эту проблему, но сейчас у меня нет такого выбора.

class Program
{
    static void Main(string[] args)
    {
        ComputeThenUpdateUI().Wait();
    } 
    static async Task ComputeThenUpdateUI()
    {
        Console.WriteLine($"1.1 {Thread.CurrentThread.ManagedThreadId}");
        await ExpensiveComputingNonUI().ConfigureAwait(true);
        Console.WriteLine($"1.2 {Thread.CurrentThread.ManagedThreadId}");
    } 
    static async Task ExpensiveComputingNonUI()
    {
        Console.WriteLine($"2.1 {Thread.CurrentThread.ManagedThreadId}");
        await Task.Delay(3000).ConfigureAwait(false);
        Console.WriteLine($"2.2 {Thread.CurrentThread.ManagedThreadId}");
        await Task.Delay(3000).ConfigureAwait(false);
        Console.WriteLine($"2.3 {Thread.CurrentThread.ManagedThreadId}");
    }
}
 
 
Output:
1.1 1
2.1 1
2.2 4
2.3 4
1.2 4

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

ConfigureAwait - это локальное решение для каждого написанного вами метода.ConfigureAwait(true) - это способ указать, что вы хотите попытаться вернуться к тому же контексту , в котором ваш метод работал при первом вводе .

Во-первых, это означает, что если вы не знаете, в каком контексте вы изначально работали в , тогда нет смысла пытаться вернуться в тот же контекст.Вы не должны пытаться делать что-либо, зависящее от контекста, если вас могут вызывать в разных контекстах.Вот почему обычно рекомендуется использовать ConfigureAwait(false), если вы создаете библиотеку.Вы не будете знать контексты, в которых вызывается ваш код.

И, во-вторых, это означает, что нет «глобального» контекста, к которому можно вернуться.Если ваш вызывающий абонент (или любой из его вызывающих абонентов и т. Д. Выше по цепочке) уже отделился от их исходного контекста вызова, нет способа (через этот механизм) вернуться кэтот контекст.

Если вы хотите переключиться на специфический контекст (такой как поток пользовательского интерфейса), и это не обязательно будет вашим вызывающим контекстом, вам нужно использовать другой, контекстныйконкретный механизм, такой как Dispatcher.Invoke() или любой другой подходящий в вашей среде.

0 голосов
/ 31 мая 2018

Re: Не означает ли .ConfigureAwait(true), что поток вернется к тому же потоку после завершения ожидания?

Нет, в большинстве случаев гарантия не предоставляется. Стивен Клири имеет однозначный ответ:

Этот «контекст» является SynchronizationContext.Current, если он не равен нулю, в этом случае это TaskScheduler.Current.(Если нет выполняемой в данный момент задачи, то TaskScheduler.Current совпадает с TaskScheduler.Default, планировщиком пула потоков).

Важно отметить, что SynchronizationContext или TaskScheduler не обязательно подразумевает определенныйнить.UI SynchronizationContext будет планировать работу для потока пользовательского интерфейса;но ASP.NET SynchronizationContext не будет планировать работу для определенного потока.

, т. е. только те вызовы, которые сделаны из потока пользовательского интерфейса, например, WPF или Windows Forms, гарантированно вернутся в тот же поток.Если вам действительно нужно вернуться к тому же потоку, то вам нужно выполнить настройку , чтобы гарантировать продолжение продолжения в исходном потоке .

Если это не является необходимым (например, дляВозврат к одному и тому же потоку, как правило, нежелателен, так как это может снизить производительность (если есть конфликт для потока) и привести к взаимоблокировкам

Re: не удается сделатьосновной метод верхнего уровня async

Теперь это возможно в C # 7.1 :

public static async Task Main(string[] args)
{
    // Can await asynchronous tasks here.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...