c# MVC里的await Task.Run线程丢失/崩溃?

2020-09-07 16:52发布

一、问题简述:

跟主线程并列的异步线程(非阻塞线程)上。

通过

await TaskRun(()=>{}};
开启新的线程并且阻塞等待的话,线程就会丢失或者崩溃。这时候用try{}catch(){}的方式也捕获不到异常。
只有一个出现在System.Web.dll内部的异常。我尝试在Vs 2015上面加载一些System.Web.pdb文件,但是没有找到合适的。

二、伪代码重新描述:

假设有同步Action和异步两个Action
public ActionResult Index()
{
DoworkAsync();
return SendHtml("ok");
}
public async Task<string> Get()
{
DoworkAsync();
return "OK";
}

然后还有两个具体工作的方法,要求按照顺序执行里面,DoworkAsync是一个同步改成异步的await Task.Run

protected async Task DoworkAsync()
    {
        int UserId
        //封装到另一方法里面也没用           
    //await DoworkAsync2();
        await Task.Run(() =>
        {
            //★重点在此处
            System.Threading.Thread.Sleep(6100);
	//真正代码               
            UserId=55;
        });

    //阻塞之后继续执行的代码
   var user = await  GetUserAsync(UserId);
    }

public async Task<UserInfo> GetUserAsync(int id)
    {
      var Reuslt  = await  Db.GetUserAsync(id);
    }
protected async Task DoworkAsync2()
    {           
        await Task.Run(() =>
        {             
            System.Threading.Thread.Sleep(6100);
	//真正代码                             
        });
    }

三、调试结果

1、线程睡眠模拟
在【★重点】那里,不管是Thread.Sleep()还Task.Delay()
都会线程崩溃。
2、实际WebRequest测试
在【★重点】那里,不管是同的方法WebRequest还是await 异步的方法GetResponseAsync
都会线程崩溃。

3、在【★重点】那里,Thread.Sleep()休眠时间为70的时候,第一次可以走到
//阻塞之后继续执行的代码
但是第二次就不行。
因为第一次是时间快,其实是已经崩溃了,【输出】窗口有:
引发的异常:“System.NullReferenceException”(位于 System.Web.dll 中)

四、结论
请问为什么会崩溃,或者求一个替换 await TaskRun(()=>{}};的方案。
因为在VS里面,假如方法名的衣面标识了async,就会提示方法体里面要有await。

标签:
3条回答
孤傲高冷的网名
2楼-- · 2020-09-07 17:19

看描述 像 async await 死锁问题。
如果action上 async 不准备加的话,底层的 async await 方法 还是把ConfigureAwait(false)加上。

查看更多
贼婆χ
3楼-- · 2020-09-07 17:22

Task.Run 里面的方法里面不要使用任何从DI获取的scope作用域的对象。 请求结束后这些对象就被释放了。

查看更多
仙女界的扛把子
4楼-- · 2020-09-07 17:28
public ActionResult Index()
{
DoworkAsync();
return SendHtml("ok");
}
public async Task<string> Get()
{
DoworkAsync();
return "OK";
}

你上面这两段代码,活还没干完,就直接return了。也就意味着DoworkAsync返回的Task你不管了,如果Task有错误,垃圾回收的时候自然在后台报错了。

问题描述感觉有点混乱,改了一下你的代码,供参考

 public async Task<string> Get()
        {
            var user = await DoworkAsync();
            return "OK";
        }

        protected async Task<UserInfo> DoworkAsync()
        {
            int userId = await Task.Run(() =>
            {
                //★重点在此处
                System.Threading.Thread.Sleep(6100);
                //真正代码
                return 55;
            });

            //阻塞之后继续执行的代码 <-- 不是阻塞,用挂起可能更合适
            return await GetUserAsync(userId);
        }

        public async Task<UserInfo> GetUserAsync(int id)
        {
            return await Db.GetUserAsync(id);
        }
查看更多
登录 后发表回答