C# 多线程 03- 使用线程池 01- 在线程池中调用委托
🏷️ 《C# 多线程》
在线程池中调用委托
异步编程模型(Asynchronous Programming Model,简称 APM),这是 .net 历史中的第一个异步编程模式。
点击查看代码
csharp
private delegate string RunOnThreadPool(out int threadId);
static void Main(string[] args)
{
int threadId = 0;
RunOnThreadPool poolDelegate = Test;
// 不使用异步处理
var t = new Thread(() => Test(out threadId));
t.Start();
// 等待 t 结束
t.Join();
// 打印结果
Console.WriteLine($"线程 Id:{threadId}");
// 开始异步处理,并指定回调函数
IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "一个代理异步调用");
// 等待 poolDelegate 执行结束
r.AsyncWaitHandle.WaitOne();
// 获取异步处理结果
// 虽然 threadId 是按址传参,但也必须通过 EndInvoke 获取返回结果
string result = poolDelegate.EndInvoke(out threadId, r);
// 打印结果
Console.WriteLine($"线程池工作线程 Id:{threadId}");
Console.WriteLine(result);
// 这里的延迟是为了给回调函数足够的执行时间
Thread.Sleep(TimeSpan.FromSeconds(2));
}
private static void Callback(IAsyncResult ar)
{
Console.WriteLine("开始一个回调");
// AsyncState 值为 BeginInvoke 的第三个参数值
Console.WriteLine($"回调状态:{ar.AsyncState}");
Console.WriteLine($"是否为线程池中的线程:{Thread.CurrentThread.IsThreadPoolThread}"); // true
// 回调函数的线程 ID 和异步处理的线程 ID 是相同的
Console.WriteLine($"线程池工作线程 Id:{Thread.CurrentThread.ManagedThreadId}");
}
private static string Test(out int threadId)
{
Console.WriteLine("开始...");
Console.WriteLine($"是否为线程池中的线程:{Thread.CurrentThread.IsThreadPoolThread}");
Thread.Sleep(TimeSpan.FromSeconds(2));
threadId = Thread.CurrentThread.ManagedThreadId;
// 返回值可以通过代理的 EndInvoke 方法获取
return $"线程池工作线程 Id 是 {Thread.CurrentThread.ManagedThreadId}";
}
打印结果
点击查看执行结果
开始...
是否为线程池中的线程:False
线程Id:3
开始...
是否为线程池中的线程:True
线程池工作线程Id:4
线程池工作线程Id是 4
开始一个回调
回调状态:一个代理异步调用
是否为线程池中的线程:True
线程池工作线程Id:4
例子中使用 r.AsyncWaitHandle.WaitOne()
方法等待操作完成,但这不是必要的。
将该代码注释掉,处理仍然可以正常执行。因为 EndInvoke
方法会等待异步操作完成。
调用 EndInvoke
方法是非常重要的,因为该方法会将任何未处理的异常抛回到调用线程中。