• 线程池-调用委托


    线程池可以成功的适应于任何需要大量短暂的开销大的资源的情形。我们事先分配一定的资源,将这些资源放入到资源池。每次需要新的资源,只需从池中获取一个,而不用创建一个新的。当该资源不再被使用时,就将其返回到池中。

    线程池是受.NET通用语言运行时(CLR)管理的。这意味着每个CLR都有一个线程池实例。ThreadPool类型拥有一个QueueUserWorkItem静态方法。该静态方法接受一个委托,代表用户自定义的一个异步操作。在该方法被调用后,委托会进入到内部队列中。如果池中没有任何线程,将创建一个新的工作线程(worker thread)并将队列中第一个委托放入到该工作线程中。

    注意:保持线程中的操作都是短暂的是非常重要的。不要在线程池中放入长时间运行的操作,或者阻塞工作线程。这将导致所有工作线程变得繁忙,从而无法服务用户操作。这会导致性能问题和非常难以调试的错误。

    线程池的用途是执行运行时间短的操作。

    我们知道 beginvoke就是通过线程的调用来异步的完成一些工作。一般只需要启动它就好,让它一直操作着。例如 用begininvoke修改界面显示,那么就是每次有所变化时它自动的改变界面的显示,因为它在后台执行着。

    但是有时候我们需要知道它的结束信息,并且在结束时还有所安排。这时候就需要endinvoke了。

    异步编程模型(Asynchronous Programming Model,简称APM)

    代码Demo:

    using System;
    using System.Threading;

    在Main方法下面加入以下代码片段:
      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);//打印出了受管理的线程ID来识别代码是被那个线程执行的
    }
    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 wrker thread id was:{0}", threadId);
    }

    在Main方法中加入以下代码片段:

    int threadId = 0;
    RunOnThreadPool poolDelegate = Test;
    var t = new Thread(() => Test(out threadId));//线程的构造函数只接受一个无任何返回结果的方法。
    t.Start();
    t.Join();//等待完成
    Console.WriteLine("Thread id:{0}", threadId);
    IAsyncResult r = poolDelegate.BeginInvoke(out threadId, Callback, "a delegate asynchronous call");
    r.AsyncWaitHandle.WaitOne();

    string result = poolDelegate.EndInvoke(out threadId, r);
    Console.WriteLine("Thread pool worker thread id:{0}", threadId);
    Console.WriteLine(result);
    Thread.Sleep(TimeSpan.FromSeconds(2));

    工作原理:

    定义了一个委托并调用BeginInvoke方法来运行该委托。BeginInvoke方法接受一个回调函数。该回调函数会在异步操作完成后会被调用,并且一个用户自定义的状态会给该回调函数。该状态通常用于区分异步调用。结果,我们得到了一个实现了IAsyncResult接口的result对象。BeginInvoke立即返回了结果,当线程池中的工作线程在执行异步操作是,扔允许我们继续其它工作。当需要异步操作的结果时,可以使用BeginInvoke方法调用返回的result对象。我们可以使用result对象的IsCompleted属性轮询结果。本例子使用的是SsyncWaitHandle属性来等待知道操作完成。当操作完成后,会得到一个结果,可以通过委托调用EndInvoke方法,将IAsyncResult对象传递给委托参数。

    注意:EndInvoke方法事实上会等待异步操作完成。调用该方法是非常重要的,因为该方法会将任何未处理的异常抛回到调用线程中。当使用这样异步API时,请确保始终调用了Begin和End方法。

    当操作完成后,传递给BeginInvoke方法的回调函数将被放置到线程池中,确切的说是一个工作线程中。如果在Main方法定义的结尾注释掉Thread。Sleep方法调用,回调函数将不会被执行。这是因为当主线程完成后,所有的后台线程会被停止,包括该回调函数。对委托和回调函数的异步调用很可能会被同一个工作线程执行。通过工作线程ID可以容易的看出。

  • 相关阅读:
    numpy通用函数
    机器学习之随机森林
    机器学习之支持向量机
    机器学习之逻辑回归
    机器学习之决策树
    机器学*之K*邻
    机器学习之线性回归
    模型之各个指标
    模型之信息熵
    模型之决策树
  • 原文地址:https://www.cnblogs.com/v-haoz/p/9265270.html
Copyright © 2020-2023  润新知