使用以下代码可以正常工作:
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,它会按预期工作。
更新1: 这两个答案都是正确的,但我只能将一个标记为答案。基于对这个问题的理解,我做了进一步的测试。我在 wrap 方法中使用了 ConfigureAwait 以使延续在 UI 以外的线程中运行:
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) 是必要的。
更新2:
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线程。</p>