Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Tip 4: Async Library Methods Shouldn't Lie

Download

Right click “Save as…”

  • MP3 (Audio only)
  • MP4 (iPhone, Android)
  • Mid Quality MP4 (Windows Phone, HTML5, iPhone)

Libraries shouldn't lie. That's not why they're called "lie-braries"...

The threadpool is an app-global resource, so you should leave the callers of your library to decide how and when they want to use it. Your library methods should not use the threadpool (Task.Run, Parallel.For, ...) internally in secret. Most of the time, they should have async signatures if and only if their internal implementations are truly async.

Slides, source code and transcript for this video are available here.

Sometimes you're forced to write a synchronous blocking method to fit into an older synchronous framework, but you still want to call new async APIs. There's no good answer here. People use Task.Wait() or Task.Result, which are bad solutions. Stephen Toub lists some less bad solutions here.

Sometimes you're trying to work in a modern asynchronous framework but you have to call legacy synchronous APIs. People use Task.Run here, but you should understand that there's simply no way to gain the scalability of async. For that you really need async all the way down. Once again, Stephen Toub fleshes out what to do here.

Tags:

Follow the Discussion

  • Love this guy. There's more tips if you click Lucian's name.

     

    #encore

  • Hi Lucian,

    I have experienced many frustrations trying to learn how to cope when sync and async worlds collide. Thanks to your educational blog-videos about async patterns and pitfalls I am starting to get a handle on the issues.

    I currently have a slight twist on meshing the synchronous and asynchronous worlds, hopefully you can provide some insight. There is an interface to a repository (IRepository ) that mostly defines CRUD operations to persist POCO models. Two actual IRepository implementations save data to a local database and the Azure table storage (either of which may take a while to handle operations), so it seems sensible for the IRepository interface definition to include async methods that return Tasks, for example:

    public interface IRepository
    {
    Task<TModel> ReadAsync<TModel>(int primaryKey) where TModel : IPrimaryKey, new();
    Task DeleteAsync<TModel>(int primaryKey) where TModel : IPrimaryKey, new();
    Task<int> InsertAsync<TModel>(TModel model) where TModel : IPrimaryKey, new();
    // ... etc ...
    }
    

    As usual, an instance of a class implementing IRepository is injected into my View Models, like:

    public class MyViewModel
    {
    private IRepository _repository;
    public MyViewModel(IRepository repository)
    {
    _repository = repository;
    }
    
    protected async Task LoadFromKeyAsync(int primaryKey)
    {
    MyPocoModel model = await _repository.ReadAsync<MyPocoModel>(primaryKey);
    // ... assimilate model info...
    }
    // view model stuff, including an async event handler that calls LoadFromKeyAsync...
    } 
    

      

    But now a situation has arisen where I need an implementation of an IRepository using in-memory data structures like a dictionary. The API for adding and reading stuff from a Dictionary consists of synchronous methods, but the IRepository interfacedefinition has async bias. So, am I being stupid by wrapping the synchronous dictionary methods using returnTask.FromResult<T>() to fulfill the IRepositorysignature requirements? For example:

     

    public class DictRepository : IRepository
    {
    Dictionary<Type, object> _dict; 
    public DictRepository()
    {
    _dict = new Dictionary<Type, object>();
    }
    
    public Task<int> InsertAsync<TModel>(TModel model) where TModel : IPrimaryKey, new()
    {
    // simplified for the sake of example...
    MockDbTable<TModel> mockDbTable = (MockDbTable<TModel>)(_dict[typeof(TModel)]);
    model.PK = mockDbTable.Keys.Max() + 1;
    mockDbTable.Add(model.PK, model);
    return Task.FromResult<int>(model.PK);
    }
    // ...
    }
    

     

    If this is a not a good idea, can you provide guidance on what to do when an interface contract you need to fulfill is async, but the specific implementation is based on synchronous methods? (of course the converse issue could also arise...)

    Thank you for your insight,

    Alan

  • JoaoJoao

    Hi,

    I'm confused about one of the "bad" uses of async and the Task-Based Asynchronous Pattern example provided here : http://msdn.microsoft.com/en-us/library/ms734701(v=vs.110).aspx

    Is it ok to do this on server side?
    I really enjoyed your Async tips, thank you.

  • @squizfloats - You've got the right idea. This is a situation where the overall API design is forcing you to have an async signature, even though your method itself isn't async in its implementation.

    Please watch the next video in the series. That discusses EXACTLY this case. Actually it discusses it in the guise of "MemoryStream". Obviously Stream has to have async APIs since most streams (disk, network, ...) are asynchronous in nature. But when you come to implement MemoryStream, it has no natural async implementation. And so it uses Task.FromResult exactly as you described.

    The video talks about several useful micro-optimizations specifically for this case. Worth considering.

  • @Joao, thanks for the pointer. I think that MSDN page has poor guidance. I'll contact the authors of it.

Remove this comment

Remove this thread

close

Comment on the Post

Already have a Channel 9 account? Please sign in