TPL如何执行';回电';

本文关键字:回电 执行 何执行 TPL | 更新日期: 2023-09-27 18:27:04

我有一个小型应用程序,它需要测试多个连接的SQL连接字符串(每个连接一次完成一个)。要做到这一点,我临时设置ConnectionTimeout = 5,以避免在连接无效时长时间等待,并设置ConnectionTimeout = 0(永远等待)。

为了避免在尝试Open()连接不好时UI挂起(即使使用ConnectionTimeout = 5,等待SqlException的时间也可能长达20秒),我想使用任务并行库(TPL)在单独的线程上运行测试。所以我开始了我的新线程:

Task<bool> asyncTestConn = Task.Factory.StartNew<bool>
    (() => TestConnection(conn, bShowErrMsg));
return asyncTestConn.Result;

问题是,这仍然锁定了UI(很明显),因为它在返回到调用者之前正在等待结果。如何允许代码将控制权返回到UI(释放GUI),同时从异步Task获得最终结果?

此外,在Task中,我可以合法地执行MessageBox.Show("Some message")吗?这对BackgroundWorkers不起作用,并且该池线程默认情况下是后台线程;然而,这似乎不是一个问题。谢谢你抽出时间。

TPL如何执行';回电';

对于TPL,ContinueWith正是您想要的。扩展Henk的答案:

var asyncTestConn = Task.Factory.StartNew(() => TestConnection(conn, bShowErrMsg));
// Henk's "MyFinishCode" takes a parameter representing the completed
// or faulted connection-testing task.
// Anything that depended on your "return asyncTestConn.Result;" statement
// needs to move into the callback method.
asyncTestConn.ContinueWith(task =>
    {
        switch (task.Status)
        {
            // Handle any exceptions to prevent UnobservedTaskException.
            case TaskStatus.Faulted: /* Error-handling logic */ break;
            case TaskStatus.RanToCompletion: /* Use task.Result here */ break;
        }
    },
    // Using this TaskScheduler schedules the callback to run on the UI thread.
    TaskScheduler.FromCurrentSynchronizationContext());

你是对的,这就是等待发生的地方:

 return asyncTestConn.Result;

您可以简单地在TestConnection()的尾部构建完成代码,或者使用Continuation:

// untested
//Task<bool> asyncTestConn = Task.Factory.Create<bool> (
Task<bool> asyncTestConn = new Task<bool> (
    () => TestConnection(conn, bShowErrMsg));
asyncTestConn.ContinueWith(MyFinishCode);
asyncTestConn.Start()

我可以合法地做MessageBox.Show("Some message")吗?

实际上是的,MessageBox是线程安全的。从Bgw也应该是可能的。

但是你延长了任务的寿命,这不是一个好主意。