After reading Eric Lippert’s answer I got the impression that await and call/cc are pretty much two sides of the same coin, with at most syntactic differences. However, upon trying to actually implement call/cc in C# 5, I ran into a problem: either I misunderstand call/cc (which is fairly possible), or await is only reminiscent of call/cc.
Consider pseudo-code like this:
function main:
foo();
print "Done"
function foo:
var result = call/cc(bar);
print "Result: " + result;
function bar(continuation):
print "Before"
continuation("stuff");
print "After"
If my understanding of call/cc is correct, then this should print:
Before
Result: stuff
Done
Crucially, when the continuation is called, the program state is restored along with the call history, so that foo returns into main and never comes back to bar.
However, if implemented using await in C#, calling the continuation does not restore this call history. foo returns into bar, and there’s no way (that I can see) that await can be used to make the correct call history part of the continuation.
Please explain: did I completely mis-understand the operation of call/cc, or is await just not quite the same as call/cc?
Now that I know the answer, I have to say that there’s a good reason to think of them as fairly similar. Consider what the above program looks like in pseudo-C#-5:
function main:
foo();
print "Done"
async function foo:
var result = await(bar);
print "Result: " + result;
async function bar():
print "Before"
return "stuff";
print "After"
So while the C# 5 style never gives us a continuation object to pass a value to, overall the similarity is quite striking. Except that this time it’s totally obvious that "After" never gets called, unlike in the true-call/cc example, which is another reason to love C# and praise its design!
await is indeed not quite the same as call/cc.
The kind of totally fundamental call/cc that you are thinking of would indeed have to save and restore the entire call stack. But await is just a compile-time transformation. It does something similar, but not using the real call stack.
Imagine you have an async function containing an await expression:
async Task<int> GetInt()
{
var intermediate = await DoSomething();
return calculation(intermediate);
}
Now imagine that the function you call via await itself contains an await expression:
async Task<int> DoSomething()
{
var important = await DoSomethingImportant();
return un(important);
}
Now think about what happens when DoSomethingImportant() finishes and its result is available. Control returns to DoSomething(). Then DoSomething() finishes and what happens then? Control returns to GetInt(). The behaviour is exactly as it would be if GetInt() were on the call stack. But it isn’t really; you have to use await at every call that you want simulated this way. Thus, the call stack is lifted into a meta-call-stack that is implemented in the awaiter.
The same, incidentally, is true of yield return:
IEnumerable<int> GetInts()
{
foreach (var str in GetStrings())
yield return computation(str);
}
IEnumerable<string> GetStrings()
{
foreach (var stuff in GetStuffs())
yield return computation(stuff);
}
Now if I call GetInts(), what I get back is an object that encapsulates the current execution state of GetInts() (so that calling MoveNext() on it resumes operation where it left off). This object itself contains the iterator that is iterating through GetStrings() and calls MoveNext() on that. Thus, the real call stack is replaced by a hierarchy of objects which recreate the correct call stack each time via a series of calls to MoveNext() on the next inner object.
Related
I have the service method returning an awaitable member view model.
public async Task<MemberVm> GetMember(Guid id)
{
Task<Member> output = Context.Members
.SingleOrDefaultAsync(e => e.Id == id);
return await output != null
? new MemberVm(output)
: null;
}
This doesn't compile because of new MemberVm(output). Instead, the computer requires me to do new MemberVm(await output). I would understand it if it was a simple return statement but in this case it's already been awaited while evaluation the conditional expression. To me it seems like this pseudo-code.
if(await output != null)
return await-again-but-why new MemberVm(output)
else
return null;
Am I doing it wrong or is it just an unintended and unfortunate consequence of the language syntax?
There's already correct answers here, but the explanations are far more complex than necessary. The await keyword both holds execution until the task completes and unwraps the task (i.e Task<Member> becomes just Member). However, you're not persisting that unwrapping part.
The second output is still a Task<Member>. It's completed now, but it isn't unwrapped because you didn't save the result of that.
If you haven't read how async..await works, you probably should to reason about it better; but what those keywords primarily do is trigger an automagical rewrite of your original code into continuation-passing style.
What basically happens is your original code is transformed into:
public Task<MemberVm> GetMember(Guid id)
{
Task<Member> output = Context.Members
.SingleOrDefaultAsync(e => e.Id == id);
return output.ContinueWith((Task<Member> awaitedOutput) =>
awaitedOutput.Result != null ? new MemberVm(output.Result) : null);
}
The original output variable remains untouched, the result of the await (so to speak) is passed into the continuation when it's available. Since you're not saving it into a variable, it's not available to you after it's first used. (It's the lambda parameter I called awaitedOutput, it's actually probably going to be something garbled the C# compiler generates if you don't assign the awaited output to a variable yourself.)
In your case it's probably easiest to just store the awaited value in the variable
public Task<MemberVm> GetMember(Guid id)
{
Member output = await Context.Members
.SingleOrDefaultAsync(e => e.Id == id);
return output != null
? new MemberVm(output)
: null;
}
You could also probably use output.Result directly in the code under the await, but that's not really how you're supposed to do things and it's slightly error-prone. (If you reassign output inadvertently to a different task for some reason. This would cause the whole thread to Wait(), and my guess is it'd just freeze.)
Crucially, it doesn't make any sense to say "a call that's already been awaited". Under the hood, await isn't a thing you do to a call or a task; it's an instruction to the compiler to take all the code following the await, pack it up into a closure, pass that to Task.ContinueWith(), and immediately return the new task. That is: await doesn't in and of itself cause a wait for the result of the call, it causes the waiting code to be registered as a callback to be invoked whenever the result is available. If you await a Task whose result is already available, all that changes is that this callback will be called sooner.
The way this achieves asynchrony is that control returns to some event loop outside your code at every point where you need to wait for a call to complete. This event loop watches for stuff to arrive "from the outside" (e.g. some I/O operation completing), and wakes up whatever continuation chain is waiting for this. When you await the same Task more than once, all that happens is that it handles several such callbacks.
(Hypothetically, yes, the compiler could also transform the code so that following an await, the original variable name refers to the new value. But there's a bunch of reasons why I imagine it's not implemented that way - the type of a variable changing mid-function is unprecedented in C# and would be confusing; and generally it seems like it'd be more complex and harder to reason about overall.)
Going on a hopefully illustrative tangent here: what I believe more or less happens when you await a Task in the same async function twice is:
Execution reaches the first await, a callback (which contains is created and passed to ContinueWith(), control returns to toplevel.
Some time later, the result of the call is available, and the callback ends up invoked with the result as the parameter.
Execution of the first callback reaches the second await, another callback is created and passed to ContinueWith()
Since the result is already available, this second callback is probably invoked immediately, and the rest of your function runs.
As you can see, awaiting the same Task twice is mostly a pointless detour through the event loop. If you need the value of the task, just put it into a variable. In my experience, a lot of the time you might as well immediately await a call to any async function, and move this statement as close to where the task result is used as you can. (Since any code after the await won’t run until after the result is available, even if it’s not using that result.) The exception is if you have some code you need to run after starting the call, but before using the result, that you can't just run before the call starts for some reason.
It doesn't compile because output is a Task, not a Member.
This would work:
public async Task<MemberVm> GetMember(Guid id)
{
Member member = await Context.Members
.SingleOrDefaultAsync(e => e.Id == id);
return member != null
? new MemberVm(member)
: null;
}
This doesn't :
Task<Member> output = Context.Members
.SingleOrDefaultAsync(e => e.Id == id);
return await output != null // <= "await output" is null or a Member instance
? new MemberVm(output) // "output" is always a Task<Member>
: null;
By writing await output "ouput" itself will not be replaced by the result of the await. It is still the same reference to the Task you created above.
Unrelated: I wouldn't recommend returning null. I guess I'd have MemberVM deal with being setup with null or throw an exception if this is a strong indication something is wrong with the application code or DB consistency.
Does this work?
What does the constructor for MemberVm look like?
public async Task<MemberVm> GetMember(Guid id)
{
var output = await Context.Members
.SingleOrDefaultAsync(e => e.Id == id);
if (output == null)
return null;
return new MemberVm(output);
}
It would seem that the constructor for MemberVm doesn't take a Task param in its constructor (although without seeing the code, I can't tell for sure). Instead, I think the constructor needs just a regular MemberVm param, so by evaluating the Context.Members... call before anything else, should help fix what you have going on. If not, let me know and we'll figure it out.
It's important to understand the the problem that the compiler flagging is a type problem. The MemberVm constructor takes a Member argument, but your output variable is of type Task<Member>. The compiler doesn't really want you to await for the Task again, but that is the most common way to extract the result from a Task and make the types work. Another way to rewrite your code is by changing the type of output:
Member output = await Context.Members.SingleOrDefaultAsync(e => e.Id == id);
Now you can pass output directly to the MemberVm constructor, because you've saved the result of the first await.
I am struggling to find any solid information online, but lets pretend I have a method like below:
public int DoSomething()
{
// some sync logic that takes a while
return someResult
}
So lets assume it is a method that is completely sync and currently will block the thread the caller is on for 100ms. So then lets say I wanted to create a version that would not block that thread while it executes, is it as simple as just doing:
public Task<int> DoSomethingAsync()
{
// some sync logic that takes a while
return Task.FromResult(someResult)
}
As I know Task.Run will cause code to be executed within a thread, but does .net basically interpret any method with a Task/<T> return type to be something that should be non blocking?
(I am hesitant to use the word async as it has mixed meanings in .net, but as shown above there is no await use here)
No. All that changing the return type does is... change the return type.
You're changing your promise from "when I return I will give you an int" to "when I return, I will give you something that will eventually provide an int" (with the caveat that the value may, in fact, already be available).
How your method comes up with the Task is entirely an internal implementation detail that is a concern for your method. In your current changed implementation, it does it by running entirely on the same thread from which it was called and then just stuffing the result into a Task at the end - to no real benefit.
If you had added the async keyword and left the return someResult; line you'd have been given more clues about this by the compiler:
This async method lacks 'await' operators and will run synchronously. Consider using ...
What I don't understand is the following snippet from MSDN:
Note that the method is now marked with the new async keyword; this is
simply an indicator to the compiler that lets it know that in the
context of this method, the keyword await is to be treated as a point
where the workflow returns control to its caller and picks up again
when the associated task is finished.
How is that any different than how non-async methods work?
If I do
int x;
x = SomeNormalFunctionThatReturnsAnInt();
Console.WriteLine(x);
or
int x;
Task<int> task = SomeAsyncFunctionThatReturnsAnInt();
x = await task;
Console.WriteLine(x);
then from the perspective of the caller, the order of execution is the exact same: an int named x is defined, a function that returns an int is run, and when that funcion is done running, its return value is set to x, which is then written to the console.
from the perspective of the caller, the order of execution is the exact same
Yes and no.
If you await all tasks as soon as they are returned to you, then yes, that method in isolation is seeing the same "order of execution". This is actually the entire point of async/await - it allows writing most asynchronous code in a way that is very natural and similar to equivalent synchronous code.
However, the caller must be aware that it has to be asynchronous. That is, the caller generally uses await, which means that it must be async. There are some added twists that come in with asynchronous code. One example: if this is executed on a UI thread, then synchronous code knows that nothing else can execute on the UI thread between SomeNormalFunctionThatReturnsAnInt and Console.WriteLine; however, asynchronous code uses await, so it must accept that anything else can execute on the UI thread between SomeAsyncFunctionThatReturnsAnInt and Console.WriteLine. So, looking at it from that context, it's not the exact same; asynchronous methods may have their "order of execution" paused while other code runs.
If you weren't waiting the result of the function x could be not initialized. But here you wait for it so there is no difference.
you need to have some read on the async and sync to see what happens in performance level ,
in your example the result is not different as you are saying the method to wait in line of await but lets have a look at the following code snippet
class Program {
private static string result;
static void Main() {
SaySomething();
Console.WriteLine(result);
}
static async Task<string> SaySomething() {
await Task.Delay(5);
result = "Hello world!";
return “Something”;
}
}
can you try to calculate the output, the result is nothing, why ?
with the await we let the main task continue as we wait 5 milliseconds before returning result, have a look at
https://msdn.microsoft.com/en-gb/library/mt674882.aspx
First, some context (pardon the pun). Consider the following two async methods:
public async Task Async1() {
PreWork();
await Async2();
PostWork();
}
public async Task Async2() {
await Async3();
}
Thanks to the async and await keywords, this creates the illusion of a nice simple call stack:
Async1
PreWork
Async2
Async3
PostWork
But, if I understand correctly, in the generated code the call to PostWork is tacked on as a continuation to the Async2 task, so at runtime the flow of execution is actually more like this:
Async1
PreWork
Async2
Async3
PostWork
(and actually it's even more complicated than that, because in reality the use of async and await causes the compiler to generate state machines for each async method, but we might be able to ignore that detail for this question)
Now, my question: Is there any way to flow some sort of context through these auto-generated continuations, such that by the time I hit PostWork, I have accumulated state from Async1 and Async2?
I can get something similar to what I want with tools like AsyncLocal and CallContext.LogicalSetData, but they aren't quite what I need because the contexts are "rolled back" as you work your way back up the async chain. For example, calling Async1 in the following code will print "1,3", not "1,2,3":
private static readonly AsyncLocal<ImmutableQueue<String>> _asyncLocal = new AsyncLocal<ImmutableQueue<String>>();
public async Task Async1() {
_asyncLocal.Value = ImmutableQueue<String>.Empty.Enqueue("1");
await Async2();
_asyncLocal.Value = _asyncLocal.Value.Enqueue("3");
Console.WriteLine(String.Join(",", _asyncLocal.Value));
}
public async Task Async2() {
_asyncLocal.Value = _asyncLocal.Value.Enqueue("2");
await Async3();
}
I understand why this prints "1,3" (the execution context flows down to Async2 but not back up to Async1) but that isn't what I'm looking for. I really want to accumulate state through the actual execution chain, such that I'm able to print "1,2,3" at the end because that was the actual way in which the methods were executed leading up to the call to Console.WriteLine.
Note that I don't want to blindly accumulate all state across all async work, I only want to accumulate state that is causally related. In this scenario I want to print "1,2,3" because that "2" came from a dependent (awaited) task. If instead the call to Async2 was just a fire-and-forget task then I wouldn't expect to see "2" because its execution would not be in the actual chain leading up to the Console.WriteLine.
Edit: I do not want to solve this problem just passing around parameters and return values because I need a generic solution that will work across a large code base without having to modify every method to pass around this metadata.
Is there an example out there showing me how the Observable.Count<TSource> Method actually works? The examples I come up with appear to return a count wrapped in an observable instead of the expected count.
For example, I expect 1 to be returned from this:
System.Diagnostics.Debug.WriteLine((Observable.Return<string>("Hello world!")).Count());
Will 1 be returned in the future (because, after all, it is an asynchronous sequence)? Or am I missing a few things fundamental? As of this writing, I actually assume that .Count() will return the results of T and grow over time as long a results are pushed out. Really? Yes.
The aggregate operators in Rx work a bit differently than in LINQ - they do not immediately return a value, they return a future result (i.e. we can only know what the final Count is once the Observable completes).
So if you write:
Observable.Return("foo").Count().Subscribe(x => Console.WriteLine(x));
>>> 1
because, after all, it is an asynchronous sequence
This actually isn't exactly true. Here, everything will be run immediately, as soon as somebody calls Subscribe. There is nothing asynchronous about this code above, there are no extra threads, everything happens on the Subscribe.
I think that using an observable that returns immediately and also using the async/await syntax as rasx did in the comments is confusing matters rather too much.
Let's create a stream with 5 elements that come back one every second and then complete:
private IObservable<long> StreamWith5Elements()
{
return Observable.Interval(TimeSpan.FromSeconds(1))
.Take(5);
}
We can call it using async/await magic as in this LINQPad friendly example:
void Main()
{
CountExampleAsync().Wait();
}
private async Task CountExampleAsync()
{
int result = await StreamWith5Elements().Count();
Console.WriteLine(result);
}
But it's misleading what's going on here - Count() returns an IObservable<int>, but Rx is super-friendly with await and converts that result stream into a Task<int> - and the await then hands back that task's int result.
When you use await against an IObservable<T>, you are implicitly saying that you expect that observable to call OnNext() with a single result and then call OnComplete(). What actually happens is that you will get a Task<T> that returns the last value sent before the stream terminated. (Similar to how AsyncSubject<T> behaves).
This is useful because it means any stream can be mapped to a Task, but it does require some careful thought.
Now, the above example is equivalent to the following more traditional Rx:
void Main()
{
PlainRxCountExample();
}
private void PlainRxCountExample()
{
IObservable<int> countResult = StreamWith5Elements().Count();
countResult.Subscribe(count => Console.WriteLine(count));
/* block until completed for the sake of the example */
countResult.Wait();
}
Here you can see that Count() is indeed returning a stream of int - to provide an asynchronous count. It will return only when the source stream completes.
In the early days of Rx, Count() was in fact synchronous.
However, that's not a terribly useful state of affairs since it "Exits the Monad" - i.e. brings you out of IObservable<T> and prevents you from further composition with Rx operators.
Once you start "thinking in streams", the asynchronous nature of Count() is quite intuitive really, since of course you can only provide a count of a stream when it's finished - and why hang around for that?? :)