c# - SynchronizationContext flows on Task.Run but not on await -
after reading stephen toub's article on synchronizationcontext i'm left question output of piece of .net 4.5 code:
private void btndosomething_click() { logsynccontext("btndosomething_click"); doitasync().wait(); } private async task doitasync() { logsynccontext("doitasync"); await performservicecall().configureawait(false); //to avoid deadlocking } private async task performservicecall() { logsynccontext("performservicecall 1"); httpresponsemessage message = await new httpclient { baseaddress = new uri("http://my-service") } .getasync("/").configureawait(false); //to avoid deadlocking logsynccontext("performservicecall 2"); await processmessage(message); logsynccontext("performservicecall 3"); } private async task processmessage(httpresponsemessage message) { logsynccontext("processmessage"); string data = await message.content.readasstringasync(); //do data } private static void logsynccontext(string statementid) { trace.writeline(string.format("{0} {1}", statementid, synchronizationcontext.current != null ? synchronizationcontext.current.gettype().name : taskscheduler.current.gettype().name)); }
the output is:
btndosomething_click windowsformssynchronizationcontext
doitasync windowsformssynchronizationcontext
performservicecall 1 windowsformssynchronizationcontext
performservicecall 2 threadpooltaskscheduler
processmessage threadpooltaskscheduler
performservicecall 3 threadpooltaskscheduler
but expect performservicecall 1 not on windowsformssynchronizationcontext since article states "synchronizationcontext.current not “flow” across await points"...
the context not passed when calling performservicecall task.run , async lambda, this:
await task.run(async () => { await performservicecall(); }).configureawait(false);
can clarify or point documentation on this?
stephen's article explains synchronizationcontext
doesn't "flow" executioncontext
(although synchronizationcontext
part of executioncontext
).
executioncontext
flowed. when use task.run
if synchronizationcontext
flow task.run
execute on ui thread , task.run
pointless. synchronizationcontext
doesn't flow, rather gets captured when asynchronous point (i.e. await
) reached , continuation after posted (unless explicitly stated otherwise).
the difference explained in quote:
now, have important observation make: flowing
executioncontext
semantically different capturing , postingsynchronizationcontext
.when flow
executioncontext
, you’re capturing state 1 thread , restoring state such it’s ambient during supplied delegate’s execution. that’s not happens when capture , usesynchronizationcontext
. capturing part same, in you’re grabbing data current thread, use state differently. rather making state current during invocation of delegate,synchronizationcontext.post
you’re using captured state invoke delegate. , when , how delegate runs implementation ofpost
method.
that means in case when output performservicecall 1
current synchronizationcontext
indeed windowsformssynchronizationcontext
because haven't yet reached asynchronous point , still in ui thread (keep in mind part before first await
in async
method executed synchronously on calling thread logsynccontext("performservicecall 1");
happens before configureawait(false)
happens on task returned performservicecall
).
you "get off" ui's synchronizationcontext
when use configureawait(false)
(which disregards captured synchronizationcontext
). first time happens on httpclient.getasync
, again on performservicecall
.
Comments
Post a Comment