Skip to content

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

🏷️ 《C# 多线程》

将 APM 模式转换为任务

关于 APM(Asynchronous Programming Model:异步编程模型)可以参考 01-在线程池中调用委托

本节介绍将 APM 转换为 Task。

csharp
/// <summary>
/// 将 APM 模式转换为任务
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
    int threadId;
    AsynchronousTask d = Test;
    IncompatibleAsynchronousTask e = Test;

    // 将 APM 转换为 TPL 的关键是 Task<T>.Factory.FromAsync 方法
    // 其中 T 为异步操作结果的类型
    // 该方法有多个重载。

    Console.WriteLine("Option 1");
    // 这种方法可以指定回调函数
    Task<string> task = Task<string>.Factory.FromAsync(
        d.BeginInvoke(
            "AsyncTaskThread",
            Callback,
            "a delegate asynchronous call"),
        d.EndInvoke);

    task.ContinueWith(t => Console.WriteLine($"Callback is finished, now running a continuation! Result: {t.Result}"));

    while (!task.IsCompleted)
    {
        Console.WriteLine(task.Status);
        Thread.Sleep(TimeSpan.FromSeconds(0.5));
    }
    Console.WriteLine(task.Status);
    Thread.Sleep(TimeSpan.FromSeconds(1));

    Console.WriteLine("------------------------------------");
    Console.WriteLine();
    Console.WriteLine("Option 2");

    // 这种方法不能直接指定回调函数
    // 如果需要,可以使用 Task.ContinueWith 方法执行回调函数。
    task = Task<string>.Factory.FromAsync(
        d.BeginInvoke,
        d.EndInvoke,
        "AsyncTaskThread",
        "a delegate asynchronous call");

    task.ContinueWith(t => Console.WriteLine($"Task is completed, now running a continuation! Result: {t.Result}"));

    while (!task.IsCompleted)
    {
        Console.WriteLine(task.Status);
        Thread.Sleep(TimeSpan.FromSeconds(0.5));
    }
    Console.WriteLine(task.Status);
    Thread.Sleep(TimeSpan.FromSeconds(1));

    Console.WriteLine("------------------------------------");
    Console.WriteLine();
    Console.WriteLine("Option 3");

    // 这里的异步方法带有 out 参数,导致 EndInvoke 的签名和 FromAsync 的签名不一致
    // 这里展示了一个小技巧,使用 lambda 表达式封装了 EndInvoke 方法
    IAsyncResult ar = e.BeginInvoke(out threadId, Callback, "a delegate asynchronous call");
    task = Task<string>.Factory.FromAsync(ar, _ => e.EndInvoke(out threadId, ar));

    task.ContinueWith(t => Console.WriteLine($"Task is completed, now running a continuation! Result: {t.Result}, ThreadId: {threadId}"));

    while (!task.IsCompleted)
    {
        Console.WriteLine(task.Status);
        Thread.Sleep(TimeSpan.FromSeconds(0.5));
    }
    Console.WriteLine(task.Status);
    Thread.Sleep(TimeSpan.FromSeconds(1));

    Console.ReadLine();
}

delegate string AsynchronousTask(string threadName);
delegate string IncompatibleAsynchronousTask(out int threadId);

static void Callback(IAsyncResult ar)
{
    Console.WriteLine("Starting a callback ...");
    Console.WriteLine($"State passed to a callback: {ar.AsyncState}");
    Console.WriteLine($"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
    Console.WriteLine($"Thread pool worker thread id: {Thread.CurrentThread.ManagedThreadId}");
}

static string Test(string threadName)
{
    Console.WriteLine("Starting...");
    Console.WriteLine($"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
    Thread.Sleep(TimeSpan.FromSeconds(2));
    Thread.CurrentThread.Name = threadName;
    return $"Thread anme: {Thread.CurrentThread.Name}";
}

static string Test(out int threadId)
{
    Console.WriteLine("Starting...");
    Console.WriteLine($"Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
    Thread.Sleep(TimeSpan.FromSeconds(2));
    threadId = Thread.CurrentThread.ManagedThreadId;
    return $"Thread pool worker thread id was: {threadId}";
}

打印结果

txt
Option 1
WaitingForActivation
Starting...
Is thread pool thread: True
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
Starting a callback ...
State passed to a callback: a delegate asynchronous call
Is thread pool thread: True
Thread pool worker thread id: 3
Callback is finished, now running a continuation! Result: Thread anme: AsyncTask
Thread
RanToCompletion
------------------------------------

Option 2
WaitingForActivation
Starting...
Is thread pool thread: True
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
Task is completed, now running a continuation! Result: Thread anme: AsyncTaskThr
ead
RanToCompletion
------------------------------------

Option 3
WaitingForActivation
Starting...
Is thread pool thread: True
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
Starting a callback ...
State passed to a callback: a delegate asynchronous call
Is thread pool thread: True
Thread pool worker thread id: 3
Task is completed, now running a continuation! Result: Thread pool worker thread
 id was: 3, ThreadId: 3
RanToCompletion