任务完成源同步上下文
TaskCompletionSource SynchronizationContext
我正在 Xamarin iOS 应用程序中编写一些基本的 Firebase 代码,并且 运行 陷入典型的死锁情况 TaskCompletionSource
。
public Task<string> GetUsers()
{
var tcs = new TaskCompletionSource<string>();
_instance.GetChild("users").ObserveSingleEvent(DataEventType.Value,
x => { tcs.SetResult(x); });
return tcs.Task;
}
当我像这样阻止此代码时:
var users = GetUsers().Result;
应用程序死锁。
如果我理解正确,回调正试图 运行 在 .Result
正在等待的同一上下文中。
我不明白的是,如果我修改代码以等待 Task
中的 GetUsers()
调用,如下所示:
var result = Task.Run(
async () => await AppContext.Database.GetUsers().ConfigureAwait(false)
).Result;
它仍然死锁。
第二种情况是怎么回事?由于 Task.Run
,代码在另一个线程上 运行 的事实不应该意味着外部 .Result
不会阻止回调调用吗?
编辑:
根据 Nkosi 的评论,我问这个问题是因为我很好奇为什么代码会阻塞。如果我等待电话
var users = await GetUsers().ConfigureAwait(false);
然后僵局就消失了。我只是想了解为什么它在包裹在 Task
中时会阻塞,因为根据我对 Task.Run
的(显然不正确的)理解,它不应该。
ObserveSingleEvent
总是将回调调度到 UI 线程(我认为所有或几乎所有的 firebase 回调都会这样做)。它不捕获同步上下文或类似的东西 - 只是总是将回调分派给 UI 线程(记住 - 它只是原生 IOS 代码的包装器)。因此,当您通过等待 Result
来阻塞 UI 线程时 - 出于明显的原因,无论您从哪个线程调用 GetUsers
,它都会死锁。您提到的链接描述了另一种情况,当被调用代码捕获当前同步上下文时,它们从没有同步上下文的后台线程调用该代码,并且回调不会发布到它。这里不是这种情况。
我正在 Xamarin iOS 应用程序中编写一些基本的 Firebase 代码,并且 运行 陷入典型的死锁情况 TaskCompletionSource
。
public Task<string> GetUsers()
{
var tcs = new TaskCompletionSource<string>();
_instance.GetChild("users").ObserveSingleEvent(DataEventType.Value,
x => { tcs.SetResult(x); });
return tcs.Task;
}
当我像这样阻止此代码时:
var users = GetUsers().Result;
应用程序死锁。
如果我理解正确,回调正试图 运行 在 .Result
正在等待的同一上下文中。
我不明白的是,如果我修改代码以等待 Task
中的 GetUsers()
调用,如下所示:
var result = Task.Run(
async () => await AppContext.Database.GetUsers().ConfigureAwait(false)
).Result;
它仍然死锁。
第二种情况是怎么回事?由于 Task.Run
,代码在另一个线程上 运行 的事实不应该意味着外部 .Result
不会阻止回调调用吗?
编辑:
根据 Nkosi 的评论,我问这个问题是因为我很好奇为什么代码会阻塞。如果我等待电话
var users = await GetUsers().ConfigureAwait(false);
然后僵局就消失了。我只是想了解为什么它在包裹在 Task
中时会阻塞,因为根据我对 Task.Run
的(显然不正确的)理解,它不应该。
ObserveSingleEvent
总是将回调调度到 UI 线程(我认为所有或几乎所有的 firebase 回调都会这样做)。它不捕获同步上下文或类似的东西 - 只是总是将回调分派给 UI 线程(记住 - 它只是原生 IOS 代码的包装器)。因此,当您通过等待 Result
来阻塞 UI 线程时 - 出于明显的原因,无论您从哪个线程调用 GetUsers
,它都会死锁。您提到的链接描述了另一种情况,当被调用代码捕获当前同步上下文时,它们从没有同步上下文的后台线程调用该代码,并且回调不会发布到它。这里不是这种情况。