异步等待导致死锁

时间:2016-03-14 12:12:38

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

我在pageload上运行了一个异步代码块。 代码运行顺畅,直到你达到capturevalue方法,我们创建一个新任务。执行该代码块等待冻结然后控件没有回来似乎代码刚刚陷入僵局

 protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            var textvalue = GetTextValueFromTask();
            txtbox.Text = textvalue.Result;
            string ss = "";
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

    private async Task<string> GetTextValueFromTask()
    {
        string strReturn = await CaptureValue();
        return strReturn;
    }

    private async Task<string> CaptureValue()
    {
        Thread.Sleep(5000);
        Task<string> T = Task.Factory.StartNew<string>(() => "hi");
        return await T;
    }

然后我在Capturevalue方法中做了一些小改动。

private async Task<string> CaptureValue()
    {
        Thread.Sleep(5000);
        Task<string> T = Task.Factory.StartNew<string>(() => "hi");
        string ss = T.Result;
        return await T;
    }

一旦我做了这个改变,它开始正常工作。它最初只取得结果有什么不同。请帮助我Iam a newbee to async

2 个答案:

答案 0 :(得分:1)

不同之处在于第二次没有发生任何&#34; await&#34;因为你自己等待任务,所以await没有做任何事情。 我想你第一次错过了await关键字,在这里:

var textvalue = await GetTextValueFromTask();

如果没有它,您的方法GetTextValueFromTask会同步运行,然后它会进入CaptureValue方法await。但是await的默认行为是它尝试捕获调用它的同步上下文并在该上下文中继续该方法的其余部分,在您的示例中它是WPF同步上下文,它不允许超过一个线程一次执行。但是延续不能继续,因为等待机制已经使用了上下文。

所以,还有一次。有一个线程(UI线程),它执行你的代码直到最后一个等待,return await T;,然后它返回给调用者 - GetTextValueFromTask,再次回到Page_Load当它被阻止时,因为最初你同步调用了GetTextValueFromTask(没有等待)。之后,您的操作T完成,您的代码尝试使用初始同步上下文WPF继续执行。但它不能,因为它已经在Page_Load等待。

评论中的link更详细地描述了这种情况。

还要考虑在async / await场景中不使用Thread.Sleep,因为它会杀死所有&#34;异步&#34;代码的本质。进一步阅读:link

另一条不直接适用于您的源代码的一般建议不是使用Task.Factory.StartNew,而是使用Task.Run。解释here

答案 1 :(得分:1)

请使用Task.Run()而不是Task.Factory.StartNew()

var T = Task.Run(() => "hi");

由Task.Run决定如何处理此任务。

另外请在await调用中使用.ConfigureAwait(false),不要求在awaiter线程上下文中继续进行。