使用线程池(1)

在线程池中调用委托

为什么要使用线程池?

创建线程是昂贵的操作,所以为每个短暂的异步操作创建线程会产生显著的开销。为了解决该问题,有一个常用的方式叫(pooling)。线程池可以成功的适应于任何需要大量短暂的开销大的资源的情形。

注意事项:

  • 每个CLR都有一个线程池实例;
  • 保持线程中的操作都是短暂的是非常重要的。不要在线程池中放入长时间运行的操作或者阻塞线程,否则会产生性能问题和非常难以调试的错误;
  • 线程池中的工作线程都是后台线程。

以下是代码实践:

using System;
using System.Threading;

namespace 在线程池中调用委托
{
    internal class Program
    {
        private static void Main()
        {
            var threadId = 0;

            RunOnThreadPool poolDelegate = Test;

            //线程的构造函数只接受一个无返回值得方法,所以用lambda表达式将Test方法的调用包起来。
            var t = new Thread(() => Test(out threadId));

            t.Start();
            t.Join();

            //Thread.Sleep(TimeSpan.FromSeconds(2));

            Console.WriteLine("Thread id: {0}", threadId);

            /*委托的异步调用,在线程池的子线程中执行委托Test函数和Callback函数在线程池中很可能在同一线程上执行,         
             * BeginInvoke接受一个回调函数,异步操作完成后调用回调函数,"a delegate asynchrous call"用户自定义
             * 状态传递给回调函数
             */
            var r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchrous call");
            r.AsyncWaitHandle.WaitOne();//等待操作完成,可省略,因为EndInvoke方法会等待异步操作的完成

            /*Test异步调用完成后,立即执行下一步操作,不等待回调函数的完成,
             * EndInvoke方法会等待异步操作的完成,
             * EndInvoke方法会将任何未处理的异常抛到调用线程里,所以BeginEnd要配对使用。
             */
            var result = poolDelegate.EndInvoke(out threadId, r);

            //Thread.Sleep(TimeSpan.FromSeconds(2));

            Console.WriteLine("Thread pool worker thread id: {0}", threadId);
            Console.WriteLine(result);

            //Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.ReadKey();
        }

        private delegate string RunOnThreadPool(out int threadId);

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

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

总结

使用BeginOperationName/EndOperationName方法和.NET中的IAsyncResult对象等方式被称为异步编程模型(APM),这样的方法称为异步方法。现代编程中更推荐任务并行库(Task Parallel Library简称TPL)

备注:学习《Multithreading in C# 5.0 Cookbook》Eugene Agafonov著的总结,以备日后查询。

posted on 2017-09-23 09:55  五月槐花  阅读(81)  评论(0编辑  收藏  举报

导航