为什么不调用 Task<T>.Result 死锁?
Why doesn't calling Task<T>.Result deadlock?
在几个月前阅读 this post 之后,我变得偏执地想得到 Task<T>
的 Result
并且不停地用一个 ConfigureAwait(false)
或 Task.Run
。但是,出于某种原因,以下代码成功完成:
public static void Main(string[] args)
{
var arrays = DownloadMany();
foreach (var array in arrays);
}
IEnumerable<byte[]> DownloadMany()
{
string[] links = { "http://google.com", "http://microsoft.com", "http://apple.com" };
using (var client = new HttpClient())
{
foreach (var uri in links)
{
Debug.WriteLine("Still here!");
yield return client.GetByteArrayAsync(uri).Result; // Why doesn't this deadlock?
}
}
}
代码打印Still here!
3次然后退出。这是特定于 HttpClient
的,调用 Result
是安全的吗(因为写它的人用 ConfigureAwait(false)
加了它)?
Task.Result
只会在某些 SynchronizationContext
出现时阻塞。在控制台应用程序中没有这样的应用程序,因此在 ThreadPool
上安排了延续。就像您使用 ConfigureAwait(false)
.
时一样
例如,在 UI 线程中,有一个可以将延续安排到单个 UI 线程。如果您使用 UI 线程与 Task.Result
同步等待,对于只能在 UI 线程上完成的任务,您会遇到死锁。
此外,死锁取决于 GetByteArrayAsync
的实现。如果它是异步方法并且它的等待不使用 ConfigureAwait(false)
,则只能死锁。
如果您愿意,可以使用 Stephen Cleary 的 AsyncContext
,它会向您的控制台应用程序添加适当的 SynchronizationContext
来测试您的代码是否可以在 UI 应用程序(或 ASP.Net).
关于 HttpClient
的(以及大多数 .NET 的)Task-returning 方法:它们在技术上不是异步的。他们不使用 async
和 await
关键字。他们只是 return 一项任务。通常是 Task.Factory.FromAsync
的包装器。所以它可能 "safe" 阻止了他们。
在几个月前阅读 this post 之后,我变得偏执地想得到 Task<T>
的 Result
并且不停地用一个 ConfigureAwait(false)
或 Task.Run
。但是,出于某种原因,以下代码成功完成:
public static void Main(string[] args)
{
var arrays = DownloadMany();
foreach (var array in arrays);
}
IEnumerable<byte[]> DownloadMany()
{
string[] links = { "http://google.com", "http://microsoft.com", "http://apple.com" };
using (var client = new HttpClient())
{
foreach (var uri in links)
{
Debug.WriteLine("Still here!");
yield return client.GetByteArrayAsync(uri).Result; // Why doesn't this deadlock?
}
}
}
代码打印Still here!
3次然后退出。这是特定于 HttpClient
的,调用 Result
是安全的吗(因为写它的人用 ConfigureAwait(false)
加了它)?
Task.Result
只会在某些 SynchronizationContext
出现时阻塞。在控制台应用程序中没有这样的应用程序,因此在 ThreadPool
上安排了延续。就像您使用 ConfigureAwait(false)
.
例如,在 UI 线程中,有一个可以将延续安排到单个 UI 线程。如果您使用 UI 线程与 Task.Result
同步等待,对于只能在 UI 线程上完成的任务,您会遇到死锁。
此外,死锁取决于 GetByteArrayAsync
的实现。如果它是异步方法并且它的等待不使用 ConfigureAwait(false)
,则只能死锁。
如果您愿意,可以使用 Stephen Cleary 的 AsyncContext
,它会向您的控制台应用程序添加适当的 SynchronizationContext
来测试您的代码是否可以在 UI 应用程序(或 ASP.Net).
关于 HttpClient
的(以及大多数 .NET 的)Task-returning 方法:它们在技术上不是异步的。他们不使用 async
和 await
关键字。他们只是 return 一项任务。通常是 Task.Factory.FromAsync
的包装器。所以它可能 "safe" 阻止了他们。