C# 异步等待导致死锁

C# 异步等待导致死锁,c#,async-await,task-parallel-library,C#,Async Await,Task Parallel Library,我在pageload上运行了一个异步代码块。 代码运行平稳,直到您到达capturevalue方法,在该方法中,我们创建了一个新任务。在执行该代码块时,等待只是冻结,然后控件不会返回,似乎代码只是进入了死锁状态 protected void Page_Load(object sender, EventArgs e) { try { var textvalue = GetTextValueFromTask();

我在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;
    }
受保护的无效页面加载(对象发送方,事件参数e)
{
尝试
{
var textvalue=GetTextValueFromTask();
Text=textvalue.Result;
字符串ss=“”;
}
捕获(例外情况除外)
{
Console.WriteLine(例如ToString());
}
}
私有异步任务GetTextValueFromTask()
{
字符串strReturn=等待CaptureValue();
返回strReturn;
}
专用异步任务CaptureValue()
{
睡眠(5000);
Task T=Task.Factory.StartNew(()=>“hi”);
返回等待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;
    }
专用异步任务CaptureValue()
{
睡眠(5000);
Task T=Task.Factory.StartNew(()=>“hi”);
字符串ss=T.结果;
返回等待T;
}

一旦我做了更改,它就开始正常工作了。它对最初获取结果有什么影响。请帮助我,我是一个异步的新手,不同的是第二次它不会发生任何“等待”,因为你自己在等待任务,所以
wait
什么都不做。 我想你第一次错过了等待关键字,这里:

var textvalue = await GetTextValueFromTask();
如果没有它,您的方法
GetTextValueFromTask
将同步运行,然后进入
CaptureValue
方法,其中出现
wait
。但是
await
的默认行为是,它尝试捕获调用它的同步上下文,并在该上下文中继续该方法的其余部分,在您的示例中,它是WPF同步上下文,不允许一次执行多个线程。但是继续无法继续,因为上下文已经被wait机制使用

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

评论中的内容更详细地描述了情况

也考虑不要在异步/等待的情况下使用<代码>线程。睡眠< /代码>,因为它杀死了代码的所有“异步”性质。进一步阅读:

另一条不直接适用于源代码的一般建议是不要使用
Task.Factory.StartNew
,而是使用
Task.Run
。说明。

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

这取决于任务。运行以决定如何处理此任务


另外,请在您的等待调用中使用.ConfigureAwait(false),该调用不需要在等待线程上下文中执行继续操作。

thread.Sleep
和等待任务的
结果
是异步代码中的一个大禁忌,特别是当涉及UI时。阅读、消化、表演:@spender如何突出注释中的单词,使其看起来像代码?thanks@FirstStep:在异步方法中启动线程是危险的。不要这样做。对于web表单,您应该坚持使用良好的旧页面异步任务(现在支持
asyncwait
)。
var T = Task.Run(() => "hi");