解析C#多线程编程中异步多线程的实现及线程池的使用

2019-12-30 11:46:49王振洲

  因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。当然异步操作也并非完美无暇。编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些出入,而且难以调试。

3、线程池的用法:

一般由于考虑到服务器的性能等问题,保证一个时间段内系统线程数量在一定的范围,需要使用线程池的概念。大概用法如下:


  public class CSpiderCtrl
  {

     //将线程池对象作为一个全局变量
    static Semaphore semaphore;

    public static void Run()
    {
      //1. 创建 SuperLCBB客户端对象
      var oClient = new ServiceReference_SuperLCBB.SOAServiceClient();

       //2.初始化的时候new最大的线程池个数255(这个数值根据实际情况来判断,如果服务器上面的东西很少,则可以设置大点)
      semaphore = new Semaphore(250, 255);

      CLogService.Instance.Debug("又一轮定时采集...");

      _TestBedGo(oClient);

    }

 

   //执行多线程的方法

   private static void _TestBedGo(ServiceReference_SuperLCBB.SOAServiceClient oClient)
    {
      List<string> lstExceptPDUs = new List<string>(){
        "SUPERLABEXP"
      };
      var oTestBedRes = oClient.GetTestBedExceptSomePDU(lstExceptPDUs.ToArray(), true);
      if (CKVRes.ERRCODE_SUCCESS != oTestBedRes.ErrCode)
      {
        CLogService.Instance.Error("xxx");
        return;
      }

      var lstTestBed = oTestBedRes.ToDocumentsEx();

      System.Threading.Tasks.Parallel.ForEach(lstTestBed, (oTestBed) =>
      {

         //一次最多255个线程,超过255的必须等待线程池释放一个线程出来才行
        semaphore.WaitOne();

        //CLogService.Instance.Info("开始采集测试床:" + oTestBed[TBLTestBed.PROP_NAME]);
        //Thread.Sleep(2000);

        var strTestBedName = oTestBed[TBLTestBed.PROP_NAME] as string;
        var strSuperDevIP = oTestBed[TBLTestBed.PROP_SUPERDEVIP] as string;
        var strTestBedGID = oTestBed[TBLTestBed.PROP_GID] as string;
        var strPdu = oTestBed[TBLTestBed.PROP_PDUGID] as string;
        Thread.Sleep(new Random().Next(1000, 5000));
        var oGetRootDevicesByTestBedGIDRes = oClient.GetRootDevicesByTestBedGID(strTestBedGID);
        CLogService.Instance.Debug(strPdu + "——测试床Name:" + strTestBedName + "开始");
        Stopwatch sp = new Stopwatch();
        sp.Start();
        if (oGetRootDevicesByTestBedGIDRes.ErrCode != CKVRes.ERRCODE_SUCCESS || oGetRootDevicesByTestBedGIDRes.Documents.Count < 2)
        {
          CLogService.Instance.Debug("shit -- 3实验室中测试床Name:" + strTestBedName + "2完成异常0");

       //这里很重要的一点,每一次return 前一定要记得释放线程,否则这个一直会占用资源
          semaphore.Release();
          return;
        }


        var strXML = oGetRootDevicesByTestBedGIDRes.Documents[0];
        var strExeName = oGetRootDevicesByTestBedGIDRes.Documents[1];
        //var strExeName = "RateSpider";


        var oSuperDevClient = new SuperDevClient(CSuperDev.ENDPOINT, string.Format(CSuperDev.SuperDevURL, strSuperDevIP));
        try
        {
          oSuperDevClient.IsOK();
        }
        catch (Exception)
        {
          CLogService.Instance.Error("测试床Name:" + strTestBedName + "异常,插件没起");
          semaphore.Release();
          return;
        }


        //2.3.1.请求SuperDev.Server(SuperDevIP),发送Run(XML和Exename)
        var oRunExeRes = new CKVRes();
        try
        {
          oRunExeRes = oSuperDevClient.RunExeEx(strExeName, false, new string[] { strXML });
        }
        catch
        {
          //CLogService.Instance.Debug("测试床Name:" + strTestBedName + "异常:" + ex.Message);
        }
        sp.Stop();
        CLogService.Instance.Debug(strPdu + "——测试床Name:" + strTestBedName + "完成时间" + sp.Elapsed);

          //每一个线程完毕后记得释放资源
        semaphore.Release();
      });
    }

  }