C# 如何在非gui线程中获取任务完成通知
背景:我过去常常在表单加载期间调用存储过程。但是,由于这导致了次优的UI体验,我将SP调用放在所示的C# 如何在非gui线程中获取任务完成通知,c#,multithreading,.net-4.0,task-parallel-library,C#,Multithreading,.net 4.0,Task Parallel Library,背景:我过去常常在表单加载期间调用存储过程。但是,由于这导致了次优的UI体验,我将SP调用放在所示的事件中的一个任务中。由于这通常是表单显示过程中的最后一个事件,因此与将内容放入表单加载事件相比,它带来了更好的体验。我有: private void MainForm_Shown(object sender, EventArgs e) { dbCheckTask = Task<bool>.Factory.StartNew(RunSPAndCheckStuff()); //
事件中的一个任务中。由于这通常是表单显示过程中的最后一个事件,因此与将内容放入表单加载事件相比,它带来了更好的体验。我有:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(RunSPAndCheckStuff());
// both of below run on the GUI thread.
// if I print the thread ID in mycallback it is the GUI thread id
dbCheckTask.ContinueWith(mycallback());
// I also tried below. But obviously, that too runs on the GUI thread
mycallback(dbCheckTask.Result)
}
private void main表单_显示(对象发送方,事件参数e)
{
dbCheckTask=Task.Factory.StartNew(RunSPAndCheckStuff());
//下面两个都在GUI线程上运行。
//如果我在mycallback中打印线程ID,它就是GUI线程ID
dbCheckTask.ContinueWith(mycallback());
//我在下面也试过了,但很明显,它也在GUI线程上运行
mycallback(dbCheckTask.Result)
}
因为它们在GUI线程上启动,所以我的启动表单绘制仍然不是即时的,也不是平滑的。如何在非GUI线程上获得任务完成回调而不诉诸事件?每当任务完成时,如果出现问题,并且只有出现问题时(bool result返回false),用户才会收到一个弹出的消息框。在那之前,他可以继续在表单上做其他与数据库无关的事情。请告知我如何在非gui线程中获得带有任务结果的任务完成回调。谢谢您应该考虑使用异步API,而不是在后台线程中调用同步版本:
这样做的好处是不会阻塞任何线程,我相信回调将在线程池线程上调用,例如,在GUI线程上不会调用。从那里,您可以使用Invoke/BeginInvoke将任何GUI调用封送回GUI线程。您应该考虑使用异步API,而不是在后台线程中调用同步版本:
这样做的好处是不会阻塞任何线程,我相信回调将在线程池线程上调用,例如,在GUI线程上不会调用。从那里,您可以使用Invoke/BeginInvoke将任何GUI调用封送回GUI线程。我个人会为此使用BackgroundWorker
。让回调在任务线程上运行的一种方法是修改方法调用和任务创建,如下所示:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(() => RunSPAndCheckStuff(mycallback));
...
}
private bool RunSPAndCheckStuff(Action<bool> callback)
{
bool result = false;
// Do stuff
callback(result);
return result;
}
private void main表单_显示(对象发送方,事件参数e)
{
dbCheckTask=Task.Factory.StartNew(()=>RunSPAndCheckStuff(mycallback));
...
}
私有bool RunSPAndCheckStuff(操作回调)
{
布尔结果=假;
//做事
回调(结果);
返回结果;
}
我个人会用一个后台工作人员来做这件事。让回调在任务线程上运行的一种方法是修改方法调用和任务创建,如下所示:
private void MainForm_Shown(object sender, EventArgs e)
{
dbCheckTask = Task<bool>.Factory.StartNew(() => RunSPAndCheckStuff(mycallback));
...
}
private bool RunSPAndCheckStuff(Action<bool> callback)
{
bool result = false;
// Do stuff
callback(result);
return result;
}
private void main表单_显示(对象发送方,事件参数e)
{
dbCheckTask=Task.Factory.StartNew(()=>RunSPAndCheckStuff(mycallback));
...
}
私有bool RunSPAndCheckStuff(操作回调)
{
布尔结果=假;
//做事
回调(结果);
返回结果;
}
为什么不这样做:
Task.Factory.StartNew(()=>WorkerMethod());
并将WorkerMethod()定义为:
否则,请提供您想要完成的更多详细信息。为什么不这样做:
Task.Factory.StartNew(()=>WorkerMethod());
并将WorkerMethod()定义为:
否则,请提供您想要完成的更多详细信息。所有这些内容都在您可以下载并拥有主页的异步语言扩展中得到了最好的解决
它将async
和await
关键字引入C#和VB,让您编写的代码可以轻松地在UI和后台线程之间来回切换,即使在单个方法中也是如此。编译器将透明地将其转换为任务、延续、错误捕获等,而您无需担心这些。您感兴趣的示例如下:
public async void AsyncSwitchToCPU() {
Console.WriteLine("On the UI thread.");
// Switch to a thread pool thread:
await new SynchronizationContext().SwitchTo();
Console.WriteLine("Starting CPU-intensive work on background thread...");
int result = DoCpuIntensiveWork();
Console.WriteLine("Done with CPU-intensive work!");
// Switch back to UI thread
await Application.Current.Dispatcher.SwitchTo();
Console.WriteLine("Back on the UI thread. Result is {0}.", result);
}
public int DoCpuIntensiveWork()
{
// Simulate some CPU-bound work on the background thread:
Thread.Sleep(5000);
return 123;
}
这甚至有一个上线许可证(微软有一些保留)。从F#那里借来的非常优雅的东西
Rgds Gert Jan所有这些内容都在您可以下载的异步语言扩展中得到了最好的解决,并且有主页
它将async
和await
关键字引入C#和VB,让您编写的代码可以轻松地在UI和后台线程之间来回切换,即使在单个方法中也是如此。编译器将透明地将其转换为任务、延续、错误捕获等,而您无需担心这些。您感兴趣的示例如下:
public async void AsyncSwitchToCPU() {
Console.WriteLine("On the UI thread.");
// Switch to a thread pool thread:
await new SynchronizationContext().SwitchTo();
Console.WriteLine("Starting CPU-intensive work on background thread...");
int result = DoCpuIntensiveWork();
Console.WriteLine("Done with CPU-intensive work!");
// Switch back to UI thread
await Application.Current.Dispatcher.SwitchTo();
Console.WriteLine("Back on the UI thread. Result is {0}.", result);
}
public int DoCpuIntensiveWork()
{
// Simulate some CPU-bound work on the background thread:
Thread.Sleep(5000);
return 123;
}
这甚至有一个上线许可证(微软有一些保留)。从F#那里借来的非常优雅的东西
Rgds Gert Jan在我看来,它应该已经可以工作了-您可以为mycallback()方法发布代码或psuedo代码吗?我相信您可以使用TaskScheduler.Default来获取未绑定到同步上下文的计划程序。您看到这个问题的事实表明TaskScheduler.Current在某个时候被设置为一个同步化的任务调度器。@Stuart。如果其他人对此问题的建议无效,将发布一些示例代码。thx@Dan谢谢你的提示。我没有设置任何与任务调度程序。代码就像我已经展示的那样。我也会从这个角度来看。在我看来,它应该已经起作用了-您可以为mycallback()方法发布代码或psuedo代码吗?我相信您可以使用TaskScheduler.Default来获取未绑定到同步上下文的计划程序。您看到这个问题的事实表明TaskScheduler.Current在某个时候被设置为一个同步化的任务调度器。@Stuart。如果其他人对此问题的建议无效,将发布一些示例代码。thx@Dan谢谢你的提示。我没有设置任何与任务调度程序。代码就像我已经展示的那样。我也会从这个角度看。哇。干净的东西。但对我的简单需求来说有点过分了。我将仔细阅读这篇文章。谢谢。干净的东西。但是有点过分了