Skip to content

C# 多线程 04-使用任务平行库 05-将 EAP 模式转换为任务

🏷️ 《C# 多线程》

将 EAP 模式转换为任务

关于 基于事件的异步模式(Event-based Asynchronous Pattern,简称 EAP)的实现方法可以参照 C# 多线程 03-使用线程池 07-使用 BackgroundWorker 组件

可以使用 TaskCompletionSource 类型将 EAP 转换为 Task。

csharp
/// <summary>
/// 将 EAP 模式转换为任务
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
    // 主要是使用 TaskCompletionSource 类型
    // T 是异步处理返回结果类型
    var tcs = new TaskCompletionSource<int>();
    var worker = new BackgroundWorker();
    worker.DoWork += (sender, eventArgs) =>
    {
        eventArgs.Result = TaskMethod("Background worker", 5);
    };

    worker.RunWorkerCompleted += (sender, eventArgs) =>
    {
        if (eventArgs.Error != null)
        {
            tcs.SetException(eventArgs.Error);
        }
        else if (eventArgs.Cancelled)
        {
            tcs.SetCanceled();
        }
        else
        {
            try
            {
                // 将 SetResult 方法封装在 try-catch 中,保证发生错误时仍然会设置给任务完成源对象
                // 若发生异常导致没有执行 SetResult,则程序会一直阻塞在获取 Task 结果那里 (tcs.Task.Result)
                tcs.SetResult((int)eventArgs.Result);
            }
            catch (Exception)
            {
                tcs.SetResult(0);
            }
        }
    };

    worker.RunWorkerAsync();
    int result = tcs.Task.Result;

    Console.WriteLine($"Result is: {result}");
    Console.ReadLine();
}

static int TaskMethod(string name, int seconds)
{
    Console.WriteLine($"Task {name} is running on a thread id {Thread.CurrentThread.ManagedThreadId}. " +
        $"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
    Thread.Sleep(TimeSpan.FromSeconds(seconds));
    return 42 * seconds;
}

打印结果

txt
Task Background worker is running on a thread id 3. Is thread pool thread: True
Result is: 210