【问题标题】:Await not freeing up the calling thread in async method等待不释放异步方法中的调用线程
【发布时间】:2012-11-03 23:03:14
【问题描述】:

我正在打印 AsyncDemoViewModel 中的 Messages 属性字符串列表。

如果我在 GetVideosSlowlyAsync() 中使用 Thread.Sleep(1000),则输出为

Time spent: 4001 milliseconds 

 - Started on thread 18, finished on thread 18  
 - Started on thread 18, finished on thread 18  
 - Started on thread 18, finished on thread 18 
 - Started on thread 18, finished on thread 18

如果我在 GetVideosSlowlyAsync() 中使用 await Task.Delay(1000),则输出为

Time spent: 4053 milliseconds 


 - Started on thread 12, finished on thread 19 
 - Started on thread 19, finished on thread 16 
 - Started on thread 16, finished on thread 19 
 - Started on thread 19, finished on thread 9

为什么 await 调用没有释放调用线程?我预计 await 版本的完成时间大约快 4 倍。

控制器代码:

public class AsyncDemoController : Controller
{
    private DepartmentDb _db;

    public AsyncDemoController(DepartmentDb db)
    {
        _db = db; 
    }

    public async Task<ActionResult> Index()
    {

        var sw = Stopwatch.StartNew();
        var v1 = await GetVideosSlowlyAsync();
        var v2 = await GetVideosSlowlyAsync();
        var v3 = await GetVideosSlowlyAsync();
        var v4 = await GetVideosSlowlyAsync();

        var vm = new AsyncDemoViewModel() {Videos = v1.Item2, Messages = new List<string>()};
        sw.Stop();
        vm.Messages.Add(string.Format("Time spent: {0} milliseconds", sw.ElapsedMilliseconds));
        vm.Messages.Add(v1.Item1);
        vm.Messages.Add(v2.Item1);
        vm.Messages.Add(v3.Item1);
        vm.Messages.Add(v4.Item1);

        return View(vm);
    }

    private async Task<Tuple<string, IEnumerable<Video>>> GetVideosSlowlyAsync()
    {
        var t1 = Thread.CurrentThread.ManagedThreadId;
        await Task.Delay(1000); // Thread.Sleep(1000);
        var t2 = Thread.CurrentThread.ManagedThreadId;
        return Tuple.Create(string.Format("Started on thread {0}, finished on thread {1}", t1, t2), _db.Videos.AsEnumerable());
    }

}

【问题讨论】:

    标签: c# .net task-parallel-library async-await


    【解决方案1】:

    await 方法等待 GetVideosSlowlyAsync 方法完成。需要将 await 移动到需要操作结果的地方:

    public async Task<ActionResult> Index()
    {
    
        var sw = Stopwatch.StartNew();
        var v1 = GetVideosSlowlyAsync();
        var v2 = GetVideosSlowlyAsync();
        var v3 = GetVideosSlowlyAsync();
        var v4 = GetVideosSlowlyAsync();
    
        var vm = new AsyncDemoViewModel() {Videos = (await v1).Item2, Messages = new List<string>()};
        sw.Stop();
        vm.Messages.Add(string.Format("Time spent: {0} milliseconds", sw.ElapsedMilliseconds));
        vm.Messages.Add((await v1).Item1);
        vm.Messages.Add((await v2).Item1);
        vm.Messages.Add((await v3).Item1);
        vm.Messages.Add((await v4).Item1);
    
        return View(vm);
    }
    

    【讨论】:

      【解决方案2】:

      您正在调用await GetVideosSlowlyAsync(),它将返回调用方法,直到任务完成。如果你想看到你期望的结果,你需要删除这个等待。这样,当Task.Delay()方法在线程池上休眠时,它将依次启动所有4个GetVideosSlowlyAsync()

      试试这样的,

      List<Task> taskList = new List<Task>();
      taskList.Add(GetVideosSlowlyAsync());
      taskList.Add(GetVideosSlowlyAsync());
      taskList.Add(GetVideosSlowlyAsync());
      taskList.Add(GetVideosSlowlyAsync());
      
      Task.WaitAll(taskList.ToArray())
      foreach (Task task in taskList)
          vm.Messages.Add(task.Result.Item1);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-09
        • 1970-01-01
        相关资源
        最近更新 更多