Reputation: 3795
C# has a cool new feature
public Task<string> async f()
{
string r = LongCompute();
return r;
}
but isn't that equivalent to
public Future<String> f() {
return Globals.executorService.submit(new Callable<String>() {
public String call() throws Exception {
String r = longCompute();
return r;
}
});
}
where in Java you have more flexibility to choose the threadpool in which the task would run.
What about await? It's equivalent to just calling get
string s = await f();
is just like
String s = f().get();
Is there anything more to C#, or is it indeed just a syntactic sugar to the Java version? (I'm not a C# guru, so I might be missing something).
Upvotes: 15
Views: 8110
Reputation: 1500893
No, await
is not like just calling get()
. There's considerably more to it.
When you use an await
expression in C#, the compiler effectively creates a continuation, so that if the awaitable hasn't completed yet, the method can immediately return, and continue processing only when it's completed. The continuation will run in an appropriate context - so if you're on a UI thread before the await
expression, you'll continue on the UI thread afterwards, but without blocking the UI thread while you're waiting for the result. For example:
public async void HandleButtonClick(object sender, EventArgs e)
{
// All of this method will run in the UI thread, which it needs
// to as it touches the UI... however, it won't block when it does
// the web operation.
string url = urlTextBox.Text;
WebClient client = new WebClient();
string webText = await client.DownloadStringTaskAsync(url);
// Continuation... automatically called in the UI thread, with appropriate
// context (local variables etc) which we used earlier.
sizeTextBox.Text = string.Format("{0}: {1}", url, webText.Length);
}
Ultimately it's all syntactic sugar, but much more complicated sugar than what you've shown.
There's a lot of detailed information available on the web already. For example:
Upvotes: 32
Reputation: 1517
Just to extend correct Jon Skeet's answer.
The is no Java analog of C# await expressions. Hoverer, some Java frameworks have same functionality:
In fact, they generate routines or state-machine code on-fly.
Upvotes: 5
Reputation: 23505
Jon didn't explain the real point.
Java's ExecutorService
is based on threads, while C#'s await
can be said to be based on fibers.
Both allow multitasking, which splits computing resources between concurrent functions (ie, functions that run "simultaneously"). The first kind of multitasking is called pre-emptive, while the second co-operative. Historically, preemptive multitasking was considered more advanced and superior to cooperative. Indeed, before preemptive multitasking became supported by consumer operating systems, computers really sucked. However, preemptive multitasking has its shortcomings. It can be hard to program for, and it uses more memory.
The main difference between the two is that preemptive multitasking allows the runtime (usually, the operating system itself) to stop any function at any time and start a different function (and to run them simultaneously on different CPUs). Meanwhile, cooperative multitasking requires the running function to end or to voluntarily pause. Most of us are familiar with preemptive multitasking in the form of multithreading, as well as the kind of careful programming that goes with it. Fewer are familiar with cooperative multitasking, which nowdays is often called fibers or coroutines (in which case it's implemented in userland inside the threads of a preemptive OS).
Anyway, the point is that ExecutorService
and await
are not directly comparable, and await
isn't, in general, superior to real multithreading (except that it features nice syntactic sugar). C#'s reason for including await
(and basing it on cooperative multitasking) is that the major GUI toolkits on the platform are not designed for multithreading and refactoring them to support concurrency would take a boatload of work. Cooperative multitasking works well for the UI because most of the event handlers are short and can be executed serially. await
extends the concept of the event loop by letting long event handlers pause themselves and resume after the rendering function gets a chance to run. All of this happens in a single thread on a single CPU core.
Where they both find common ground is that they're both forms of multitasking, and Future.get
and await Task
are both forms of synchronization.
As can be expected, C# is not without good support for threads and thread pools. Likewise, Java contains fibers/co-routines/async in many libraries, such as Servlet 3.0 and javafx.concurrent.Task
.
In response to Jon Skeet: Continuation (as the userland implementation mechanism of fibers is called) is non-trivial, but threads are no less sophisticated in their implementation. Jon may have been thrown off because the algorithms behind threads are in the OS rather than in the compiler or .NET runtime.
Upvotes: 12