c# – 为什么Task.Result在这种情况下不起作用?
它使用以下代码正常工作:
private void button1_Click(object sender,EventArgs e) { Task<int> t = test(5); Console.WriteLine(t.Result); } private Task<int> test(int n) { return Task.Run(() => { return n; }); } 但是,如果我使用异步方法包装测试方法,它不起作用: private Task<int> test(int n) { return Task.Run(() => { return n; }); } public async Task<int> wrap() { return await test(5); } private void button1_Click(object sender,EventArgs e) { Task<int> t = wrap(); Console.WriteLine(t.Result); } 表格失去了回应.如果我使用await,它会按预期工作. UPDATE1: public async Task<int> wrap() { return await test(5).ConfigureAwait(false); } 它工作正常.然后我测试了这个: public async Task<int> wrap() { int i = await test(5).ConfigureAwait(false); int j = i + await test(3); return j; } 它在我第一次单击按钮时工作,但在第二次单击时再次死锁.如果我在test(3)之后添加了ConfigureAwait(false),就像这样: public async Task<int> wrap() { int i = await test(5).ConfigureAwait(false); int j = i + await test(3).ConfigureAwait(false); return j; } 它再次运作,但这对我来说没有意义.由于第一个ConfigureAwait(false),wrap()中的所有以下同步部分都应该在非UI线程上运行.我不明白为什么第二个ConfigureAwait(false)是必要的. UPDATE2: private Task<int> test(int n) { return Task.Run(() => { Console.WriteLine("test(" + n + "): " + System.Threading.Thread.CurrentThread.ManagedThreadId); return n; }); } public async Task<int> wrap() { Console.WriteLine("1.wrap(): " + System.Threading.Thread.CurrentThread.ManagedThreadId); int i = await test(5).ConfigureAwait(false); Console.WriteLine("2.wrap(): " + System.Threading.Thread.CurrentThread.ManagedThreadId); int j = i + await test(3); Console.WriteLine("3.wrap(): " + System.Threading.Thread.CurrentThread.ManagedThreadId); return j; } private void button1_Click(object sender,EventArgs e) { try { Console.WriteLine("1.button1_Click(): " + System.Threading.Thread.CurrentThread.ManagedThreadId); var t = wrap(); Console.WriteLine("2.button1_Click(): " + System.Threading.Thread.CurrentThread.ManagedThreadId); Console.WriteLine(t.Result); } catch (Exception ex) { Console.WriteLine(ex.Message); } } 几次单击后,表单冻结,输出为: 1.button1_Click(): 8 1.wrap(): 8 test(5): 13 2.wrap(): 8 2.button1_Click(): 8 test(3): 13 令我惊讶的是,“2.wrap():”与“1.wrap():”在同一个线程中运行,而不是“test(5)”.似乎ConfigureAwait(false)之后的代码也可以跳回UI线程. 解决方法
这是一个死锁 – 在单线程调度程序中运行的两个任务正在等待彼此完成.
理解这两个非常重要的事情: >默认情况下,await的结果返回到与其开始时相同的调度程序. 因此,您需要特别注意如何在UI调度程序内部执行的Task上调用阻塞方法. 在第二个示例中,对Result的调用正在等待包装中的继续设置完成.延迟计划在UI线程上运行,对Result的调用恰好是阻塞,因此两者都不会完成. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |