嵌套的异步方法和线程池Asp.Net

时间:2015-09-24 14:45:39

标签: c# asp.net asynchronous async-await

我正在构建一个async Web Api,在阅读了一些关于async / await的文章后,我认为我做错了。

这是我的实际代码:

public async Task<IHttpActionResult> GetAccount(int id)
{
    var i = await GetInstanceIdAsync(User, _db); //grabs a thread
    ...
}

public async static Task<int> GetInstanceIdAsync(IPrincipal user, Entities db)
{
    var userManager = 
         new UserManager<ControliUser>(new UserStore<ControliUser>(db));
    //next line grabs another thread but since it was called from an await
    //it holds 2 threads, am I correct?
    var u = await userManager.FindByNameAsync(user.Identity.Name);
    return u == null ? 0 : u.InstanceId ?? 0;
}

所以我的第一个问题是,这会消耗2个线程吗?

如果答案是肯定的,那么我就采用了这种扩展方法来防止这种情况。

public static Task<int?> InstanceIdAsync(this Entities db, IPrincipal user)
{
    var userManager = new UserManager<ControliUser>(new UserStore<ControliUser>(db));
    return userManager.FindByNameAsync(user.Identity.Name).ContinueWith(t =>
    {
        if (t.IsCompleted && t.Result != null)
            return t.Result.InstanceId;
        return null;
    });
}

我认为这个方法只消耗1个线程并减少开销,因为它保存了async方法

我是否正确?

1 个答案:

答案 0 :(得分:3)

  

所以我的第一个问题是,这消耗了2个线程吗?

没有。使用 async-await 不会产生任何额外的线程使用。相反,它在异步操作正在进行时释放线程。这意味着线程将被使用,直到调用FindByNameAsync,然后它将被释放,只有在该操作完成后才能恢复。然后,它将在任意线程池线程上恢复操作(第一个await之后的代码),同时保留请求上下文。

  

我认为这种方法只消耗1个线程并减少开销   因为它保存了一个异步方法

首先,这在WebAPI中不起作用。问题是继续只会在第一个任务完成后执行。反过来,这将通知正在进行的IO操作的同步上下文,并将导致异常。

如前所述,async方法不生成任何线程使用,它只是创建一个 状态机 ,因此它可以调用你的继续方法(在第一个await之后的任何调用)正确。