Zrozumienie kontekstu w C # 5 asynchronicznym /

Czy mam rację, że asynchronizacja / oczekiwanie nie ma nic wspólnego z współbieżnością / paralelizmem i jest niczym więcej niż implementacją stylu kontynuacji (CPS)? A prawdziwy wątek jest wykonywany przez SynchronizationContext instancję, która await przekazuje/przywraca?

Jeśli to prawda mam następujące pytanie odnośnie SynchronizationContext:
gwarantuje to, że kontynuacja zostanie wykonana w tym samym wątku.

Czy są jednak jakieś gwarancje, że informacje kontekstowe wątku są utrzymywane? To znaczy Name, CurrentPrincipal, CurrentCulture, CurrentUICulture, itd. Czy to zależy od frameworka (ASP.NET, WinForms, WCF, WPF)?

Author: AaronLS, 2012-09-17

2 answers

Czy mam rację, że asynchronizacja / oczekiwanie nie ma nic wspólnego z współbieżnością/równoległością i jest niczym więcej niż implementacją CPS?

Cóż, async / await to przepisywanie, które wykorzystuje CPS, więc twoje podstawowe zrozumienie jest poprawne.

Jeśli chodzi o" współbieżność " i "równoległość", powiedziałbym, że włącza współbieżność; możesz uruchomić wiele operacji async, które są" w locie " w tym samym czasie. Jest to łatwe do zrobienia z Task.WhenAll i Task.WhenAny.

Mimo, że async samo w sobie nie oznacza "wielowątkowości", Task.Run umożliwia łatwe async-kompatybilne wielowątkowość

I prawdziwe wątki są wykonywane przez instancję SynchronizationContext, która czeka na podanie/przywrócenie?

Pomyśl o tym w ten sposób: kontynuacja stworzona przez CPS przepisywanie musi biegać gdzieś . Przechwycony "kontekst asynchroniczny" może być użyty do zaplanowania kontynuacji.

Side note: the captured kontekst jest właściwie SynchronizationContext.Current chyba że jest to null , w którym to przypadku przechwycony kontekst to TaskScheduler.Current.

Kolejna ważna uwaga: przechwytywanie i przywracanie kontekstu zależy w rzeczywistości od obiektu "awaiter". Domyślnie, jeśli await A Task (lub jakikolwiek inny wbudowany), kontekst zostanie przechwycony i przywrócony. Ale jeśli await wynik ConfigureAwait(false), to kontekst nie zostanie uchwycony. Podobnie, jeśli await twój własny zwyczaj nie uchwyci kontekstu (chyba programujesz do).

Czy są jednak jakieś gwarancje, że informacje kontekstowe wątku są utrzymywane? Mam na myśli nazwę, pryncypał, CurrentCulture, Currenttuiculture itp.

SynchronizationContext jest inny niż ExecutionContext. Uproszczoną odpowiedzią jest to, że ExecutionContext zawsze "płynie", więc CurrentPrincipal płynie (jeśli nie, może to być problem bezpieczeństwa, dlatego API, które nie przepływają ExecutionContext zawsze kończą się Unsafe).

W aplikacjach interfejsu, kultura nie płynie, ale domyślnie jest to tak samo dla wszystkich wątków. Name na pewno nie będzie płynąć, chyba że wznowisz w tym samym wątku (np. używając interfejsu SynchronizationContext).


Do dalszej lektury polecam zacząć od mojego async / await tutorial a następnie oficjalny async / await FAQ . Następnie spójrz na Stephen Toub ' s blog post na ExecutionContext vs.SynchronizationContext.

Możesz również znaleźć moje SynchronizationContext artykuł pomocny.

 33
Author: Stephen Cleary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-17 13:23:41

No, the async/await słowa kluczowe mają wszystko wspólnego z współbieżnością. async/await zasadniczo zawiń kod metody w zadanie i kontynuację. Aby zobaczyć dokładne tłumaczenie, które kompilator produkuje (używając Biblioteki Task Parallel Library), należy zdemontować fragment kodu. To tłumaczenie async/await użycie jest " podobne "(ale nie identyczne!) do poniższego przykładu

async Task<int> TaskOfTResult_MethodAsync()
{
    int hours;
    // . . .
    // Return statement specifies an integer result.
    return hours;
}

// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();

Jest to ok.]}

private int Result()
{
    int hours;
    // . . .
    // Return statement specifies an integer result.
    return hours;
}

Gdzie czekasz na zwrot poza metodą jak

int? hours = null;
Task<int> task = null;
task = Task.Factory.StartNew<int>(() => Result());
task.ContnueWith(cont => 
{
    // Some task completion checking...
    hours = task.Result;
}, CancellationToken.None, 
   TaskCreationOptions.None, 
   TaskScheduler.Current);

Lub możesz umieścić kod TPL w metodzie Result

private int ResultAsync()
{
    int? hours = null;
    Task<int> task = null;
    task = Task.Factory.StartNew<int>(() => 
    {
        int hours;
        // . . .
        // Return statement specifies an integer result.
        return hours;
    }, CancellationToken.None, 
       TaskCreationOptions.None, 
       TaskScheduler.Current);
    try
    {
        return task.Result;
    }
    catch (AggregateException aggEx)
    {
        // Some handler method for the agg exception.
        aggEx.Handle(HandleException); 
    }
}

SynchronizationContext nie gwarantuje, że kontynuacja zostanie wykonana w tym samym wątku dla async/awate Kod. Można jednak ustawić kontekst za pomocą kodu TPL, za pomocą słowa kluczowego SynchronisationContex.

 4
Author: MoonKnight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 16:39:00