Async articles

Async articles

Rate This
  • Comments 8

I am pleased to announce that MSDN Magazine is doing a special issue this month on the new "async-await" feature that we are working on for the next versions of C# and Visual Basic. If this subject interests you, see my introductory article for beginners, Mads Torgersen's article on how it works behind the scenes and Stephen Toub's expert-level article on async performance. And of course, for a much longer introduction to the topic, see my long series from earlier this year. If you want to try it out yourself, download the CTP build from the async CTP main page.

Please do keep the great feedback coming! If you have comments, questions or constructive feedback on any aspect of the new feature, please post it to the async forum. Thanks!

 

  • I read your long series awhile back, and I just read your MSDN article yesterday. You should write a series of blog posts on how you learned to write and communicate.

    That's kind of you to say. Basically, it comes down to three things. (1) Know what you want to say. (2) Break it down such that each sentence conveys one idea and each paragraph conveys one topic. (3) Practice. Lots and lots of practice. Active practice, where you constantly strive to self-criticize and do better. Seven hundred blog articles and fifteen hundred StackOverflow posts and about fifty thousand emails add up to a lot of practice! -- Eric

     

     

  • I like to avoid switching to new .NET Framework versions if not absolutely necessary, so as to avoid asking the user to download a (giant) upgrade. When LINQ came out, I was delighted to learn that I could use LINQ with .NET 2.0 even though it was not included with the .NET 2.0 BCL, thanks to a gem called LinqBridge.

    The await/async feature, similarly, depends on classes implemented in the BCL. Will it be possible to use a 3rd-party implementation of Tasks in order to use await/async in .NET 3.5 or even 2.0?

  • Qwertie has a point. I'll also add the question: will it be possible to use the c# 5.0 compiler (await/async) while targetting .NET 4.0?

  • A long time ago on this blog, someone pointed out that there are similarities between async methods and iterator blocks. In both cases the compiler transforms your single method into a class and a state machine, and in principle it appears that the async feature could be used to simulate a iterator method (or vice versa). However, the relationship between the two is fuzzy in my mind and could use some clarification.

    However, what interests me most is the question of whether the async methods are in some way equivalent to Cω's stream flattening. Since C# iterators are not flattened, performance suffers when using them to enumerate any tree-like data structure or state space... I wrote about this at loyc-etc.blogspot.com/.../c-stream-flattening.html .

    So, if async methods provide flattening (and I think they do), in principle someone could use them to write an iterator that walks a tree (using code that is easy-to-write and O(1) per tree node). I fear, however, that

    (1) the way the "scheduling context" concept was designed may prevent the use of async methods as iterators, because Mads says "Scheduling context is a thread-affine concept; every thread has (at most) one."

    (2) even if there is a workaround for problem (1), their efficiency would be limited by the fact that they are seemingly not designed for enumeration and therefore require some kind of wrapper code (to convert Task=>IEnumerator) that might introduce a lot of overhead. Disclaimer: I may not know what I'm talking about, not having written any C# with async yet.

    I would love to see an example of walking a binary tree or a directory tree using an async method, especially if it were somehow transformed into an IEnumerator.

  • I don't quite get the purpose of the language changes. How is async/await business better than the following:

    static class Async {

    public static Task Call(Action action) {

    var t = new Task(action); t.Start(); return t;

    }

    .... // other overloads

    }

    And then, in the famous "data copy" method:

    void ArchiveDocuments(List<Url> urls)

    {

     Task archive = null;

     for(int i = 0; i < urls.Count; ++i)

     {

       var document = Fetch(urls[i]); // notice, we're just calling the sync. version

       if (archive != null)

         archive.Wait();

       archive = Async.Call(()=> Archive(document));

     }

    }

    Voila. No C# changes, no state machines, nada. This is actually better because we don't have to write yet another version of each method: ReadAsync in addition to Read, ReadBegin/ReadEnd, etc. In the example above, we can use existing synchronous Fetch() and Archive(), which means less word writing and testing and maintaining code.

  • PS. I understand that to be able to handle expressions and complex statements, however, we could've just added "await" keyword which basically calls task.Wait() and returns task.Result, like so:

    var a_ = Async.Call(()=>GetNumber());

    ...

    int x = await a_ + 5;

    The await keyword above introduced very minimal changes, again, no need to re-write the method entirely, etc.

  • PPS. On the same note, the "archive.Wait();" line can be replaced with "await archive;" and "archive = Async.Call(()=> Archive(document));" line can be replaced with "archive = async Archive(document);" - again, very easy changes and no need to write new, "async" versions of existing methods.

    Personally, I will probably not use the async/await keywords, because they force me to do more work, not less work.

  • It's not clear why await isn't allowed in a catch block. Is that because an empty throw statement wouldn't have an exception context if invoked from a continuation? If that's the case, it seems like an empty throw and await could just be made mutually exclusive.

    My guess is that rethrowing is pretty rare to begin with, and there's not much intersection where you'd want to await something and want to rethrow. I imagine that rethrowing usually happens in instances where you want to perform some action (like logging) as an exception makes its way up the stack (like a finally clause that only executes when there's an exception). On the other hand, I imagine that awaiting in a catch block would likely happen because Async Operation A failed so you want to try Async Operation B instead.

Page 1 of 1 (8 items)