大家好,我是Edison。
去年换工作时系统复习了一下.NET Core多线程相关专题,学习了一线码农老哥的《.NET 5多线程编程实战》课程,我将复习的知识进行了总结形成本专题。
深入分析使用Result方法死锁的原因.
场景1:带有同步上下文的编程模型中有可能会出现死锁
例如:WindowsForm、WPF
场景2:同步+异步的场景中也有可能出现死锁
Result => 同步等待,它其实违背了异步编程的理念(初心)
同步+异步混用会异常复杂,产生的Bug不易发现
比如:在WindowsForm下,同步调用异步方法(task.GetResult())时,async的callback进入了Queue,而主线程需要不断地读取Queue的内容来执行,就容易造成死锁。
为什么会出现死锁?
主线程 要结束阻塞,必须要等待 延续Task 执行完毕
延续Task 要执行完毕,必须要 主线程 从Queue中调取执行
var content = await client
.GetStringAsync("http://cnblogs.com")
.ConfigureAwait(false);
private async void button1_Click(object sender, EventArgs e)
{
var content = await GetContent();
textBox1.Text = content;
}
private void button1_Click(object sender, EventArgs e)
{
var task = Task.Run(() =>
{
var content = GetContent().Result;
return content;
});
textBox1.Text = task.Result;
}
private void button1_Click(object sender, EventArgs e)
{
SqlConnection connection = new SqlConnection("Server=LocalHost; Persist Security Info=False;Integrated Security=SSPI;Database= PostDB;");
var length = connection.ExecuteScalarAsync<int>("select count(1) from Post").Result;
textBox1.Text = length.ToString();
}
await Task.Delay(1000 * 3);
yield return urls;
foreach (var url in await urlsTask)
{
if (url.Contains("csdn") || url.Contains("cnblogs"))
yield return url;
}
while (await reader.ReadAsync())
{
yield return reader;
}
foreach (var url in urls)
{
tasks.Add(client.GetStringAsync(url));
if (tasks.Count == 2)
{
var strlist = await Task.WhenAll(tasks);
Console.WriteLine($"{DateTime.Now}, length1={strlist[0].Length}, length2={strlist[1].Length} tid={Environment.CurrentManagedThreadId}");
tasks.Clear();
}
}
if(t.IsFaulted)
{
t.Exception.Handle(m => true);
}
方式2:不处理,往外抛
if(t.IsFaulted)
{
t.Exception.Handle(m => false);
}
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
Console.WriteLine(e.Exception.Message);
Console.WriteLine($"tid={Environment.CurrentManagedThreadId}");
};
GC.Collect(); // 仅用来测试