我有一个启动窗口(在WPF中)的应用程序,它允许用户登录,选择数据库,进行一些其他设置,最终(成功时)显示进度条。完成进度后,将显示一个主窗口(在WinForms中)。
为了使进度条顺利更新,我尽可能地远离UI线程。这是目前的做法:
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
var backgroundScheduler = TaskScheduler.Default;
var connectingTask = Task.Factory.StartNew(() =>
{
System.Diagnostics.Debug.WriteLine("connecting started");
// some code that connects to a server; may fail
System.Diagnostics.Debug.WriteLine("connecting finishing");
}
var connectFailAction = new Action<Task>((t) =>
{
System.Diagnostics.Debug.WriteLine("connectFail started");
// let user know that connecting failed, then exit
System.Diagnostics.Debug.WriteLine("connectFail finishing");
});
var postConnectAction = new Action<Task>((t) =>
{
System.Diagnostics.Debug.WriteLine("postConnect started");
// some initial post-connection setup code; runs in UI thread
System.Diagnostics.Debug.WriteLine("postConnect finishing");
});
var dbLoadingAction = new Action<Task>((t) =>
{
System.Diagnostics.Debug.WriteLine("dbLoading started");
// code that loads settings from the database; runs in background
System.Diagnostics.Debug.WriteLine("dbLoading finishing");
});
var runGuiAction = new Action<Task>((t) =>
{
System.Diagnostics.Debug.WriteLine("runGui started");
// set up the main form, show it, hide this startup progress window
System.Diagnostics.Debug.WriteLine("runGui finishing");
});
connectingTask.ContinueWith(connectFailAction,
System.Threading.CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
uiScheduler);
connectingTask.ContinueWith(postConnectAction,
System.Threading.CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion,
uiScheduler)
.ContinueWith(dbLoadingAction,
System.Threading.CancellationToken.None,
TaskContinuationOptions.None,
backgroundScheduler)
.ContinueWith(runGuiAction,
System.Threading.CancellationToken.None,
TaskContinuationOptions.None,
uiScheduler);
如果连接失败,任务将直接转到connectFailAction
。
否则,在UI线程上,接下来会运行postConnectAction
,同时在后台运行dbLoadingAction
。然后,runGuiAction
运行。
这大部分工作正常,但是一个奇怪的边缘情况是CefSharp
。具体来说,UI的非CefSharp部分被卡住了。 - 我无法调整表单大小,我无法与任何控件等进行互动。
由于等效代码适用于WinForms WebBrowser
控件,我猜测它部分是CefSharp的问题,但部分原因可能是我对TPL的错误使用/理解。
如果我按如下方式更改代码,UI会在加载过程中卡住(不出所料),但CefSharp会正确进入。
connectingTask.ContinueWith(connectFailAction,
System.Threading.CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
uiScheduler);
connectingTask.Wait();
postConnectAction.Invoke(null);
dbLoadingAction.Invoke(null);
runGuiAction.Invoke(null);
如果(并且仅当)使用CefSharp,主线程卡在System.Windows.Threading.DispatcherSynchronizationContext.Wait
中,所以我猜测上述任务之一从未干净地完成,导致事件队列无法正常刷新?< / p>
答案 0 :(得分:1)
主线程卡在
System.Windows.Threading.DispatcherSynchronizationContext.Wait
中,所以我猜测上述任务之一从未干净地完成,导致事件队列无法正常刷新?
问题是后一个示例中的代码死锁。您正在调用稍后尝试在UI线程上运行延续的Task
,该线程当前被connectingTask.Wait();
阻止。这就是you shouldn't block on async code.
关于CefSharp,也许连接后在UI线程上运行的延续是CPU密集型的,并导致UI消息循环停止超过一段合理的时间。由于您未提供相关代码,因此无法确定。