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)?
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
.
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.
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
.
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