服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#实现控制线程池最大数并发线程

C#实现控制线程池最大数并发线程

2021-12-02 13:51itshare C#

这篇文章主要介绍了C#实现控制线程池最大数并发线程的相关资料,需要的朋友可以参考下

1. 实验目的:

      使用线程池的时候,有时候需要考虑服务器的最大线程数目和程序最快执行所有业务逻辑的取舍。
并非逻辑线程越多也好,而且新的逻辑线程必须会在线程池的等待队列中等待 ,直到线程池中工作的线程执行完毕,
才会有系统线程取出等待队列中的逻辑线程,进行cpu运算。

2.  解决问题:

     <a>如果不考虑服务器实际可支持的最大并行线程个数,程序不停往线程池申请新的逻辑线程,这个时候我们可以发现cpu的使用率会不断飙升,并且内存、网络带宽占用也会随着逻辑线程在cpu队列中堆积,而不断增大。

      <b>如果我们想在主程序有200个http网络通讯需要执行,如何每次循环用10个线程并发处理10个网络http通讯回话,下一次循环只有在上一次循环的10个线程都执行完毕后才会执行下一次循环,并且主程序监听和等待200个http网络通讯都在cpu线程池中执行完毕后,才会退出主程序。

 3.  实现逻辑:

      我们通过两个autoresetevent和线程监听器monitor,分别实现:

       <a>wait_sync:   任务线程的 并发执行,每次循环只处理最大10个线程分别对网络做http通讯回话。并且当前循环的10个线程都执行完毕后,才会进行下一次循环处理。
       <b> wait_main: 主程序线程的监听和等待,只有所有任务线程都执行完毕后,主程序线程才会退出程序。
       <c> list_thread: 负责记录每次循环,cpu实际分配的系统线程的个数。和monitor配合使用,monitor.enter(list_thread)=占用共享线程资源的占用锁,monitor.exit(list_thread)释放共享线程资源的占用锁。  
       <d> n_total_thread: 配合wait_main使用,记录全部逻辑线程,已经执行完毕的当前总个数,用来判断主线程是否还需要继续等待,还是可以结束主程序运行。

4. 主要代码:

    <a> 线程池控制代码,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/// <summary>
/// 多线程调用wcf
/// </summary>
/// <param name="select">调用wcf的方式,1=restful,2=tcp</param>
/// <param name="num"></param>
static void dotest_multithread(string select, long num)
{
  int n_max_thread = 10; // 设置并行最大为10个线程
  int n_total_thread = 0; // 用来控制:主程序的结束执行,当所有任务线程执行完毕
 
  ilog log_add = new loghelper("add_thread");
  ilog log_del = new loghelper("del_thread");
  ilog log_wait = new loghelper("wait_thread");
  ilog log_set = new loghelper("set_thread");
  ilog log_for = new loghelper("for_thread");
 
  console.title = string.format("调用wcf的方式 => {0}, 调用次数=> {1}"
    , select == "1" ? "restful" : "socket"
    , num);
   
  list<int> list_thread = new list<int>();
 
  system.threading.autoresetevent wait_sync = new system.threading.autoresetevent(false); // 用来控制:并发最大个数线程=n_max_thread
  system.threading.autoresetevent wait_main = new system.threading.autoresetevent(false); // 用来控制:主程序的结束执行,当所有任务线程执行完毕
 
  datetime date_step = datetime.now;
  for (long i = 0; i < num; i++)
  {
    num_query_static++;
    if (i >0 && (i+1-1) % n_max_thread == 0) // -1 表示第max个线程尚未开始
    {
      //log_wait.info(string.format("thread n= {0},for i= {1}", dic_thread.count, i + 1));
      wait_sync.waitone(); // 每次并发10个线程,等待处理完毕后,在发送下一次并发线程
    }
    log_for.info(string.format("thread n= {0},for i= {1}", list_thread.count, i + 1));
 
    system.threading.threadpool.queueuserworkitem
      ((data) =>
      {
        int id = system.threading.thread.currentthread.managedthreadid;
        system.threading.monitor.enter(list_thread);
        list_thread.add(id);
        system.threading.monitor.exit(list_thread);
 
        log_add.info(string.format("id={0}, count={1}", id, list_thread.count)); // 日志
 
        if (select == "1") // restful方式调用
        {
          query_htty();
        }
        else
        {
          query_socket();
        }
 
        n_total_thread += 1;
        if (list_thread.count == (n_max_thread) || n_total_thread == num)
        {
          list_thread.clear();
          //log_set.info(string.format("thread n= {0},for i= {1}", dic_thread.count, i + 1));
          //wait_sync.set();
          if (n_total_thread != num)
          {
            wait_sync.set(); // 任务线程,继续执行
          }
          else
          {
            wait_main.set(); // 主程序线程,继续执行
          }
        }
      }, list_thread);
  }
 
  wait_main.waitone();
 
  console.writeline(string.format("总测试{0}次,总耗时{1}, 平均耗时{2}"
    , num
    , (datetime.now - date_step).tostring()
    , (datetime.now - date_step).totalmilliseconds / num));
 
  query_thread();
}

 <b> wcf后台服务代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static ilog log = new loghelper("seqservice"); // 日志
private static dictionary<int, datetime> dic_thread = new dictionary<int, datetime>(); // 线程列表
 
private static long num = 0; // 线程个数
private static object lock_num = 0; // 共享数据-锁
 
/// <summary>
/// 在线申请流水号
/// </summary>
/// <returns></returns>
[webget(uritemplate = "getseqnum/json", responseformat = webmessageformat.json)]
public string getseqnumber()
{
  lock (lock_num)
  {
    num++;
    int id_thread = system.threading.thread.currentthread.managedthreadid;
    datetime now = datetime.now;
    if (!dic_thread.trygetvalue(id_thread, out now))
    {
      dic_thread.add(id_thread, datetime.now);
    }
 
  }
  string ret = datetime.now.tostring("yyyymmdd") + num.tostring(new string('0', 9));
 
  log.info(string.format("{0}, thread={1}/{2}", ret, system.threading.thread.currentthread.managedthreadid, dic_thread.count));
  return ret;
}
  

5.  实验结果

1. 10000个wcf网络http请求,cpu分成每次10个(10可以按需求调整)线程并发执行,并且主程序在所有请求都执行完毕后,才退出主程序。

C#实现控制线程池最大数并发线程

1. 前端日志:logfile\add_thread\info

C#实现控制线程池最大数并发线程

2. wcf日志:logfile\seqservice\info

C#实现控制线程池最大数并发线程

原文链接:http://www.cnblogs.com/itshare/archive/2016/07/31/5722148.html

延伸 · 阅读

精彩推荐
  • C#深入理解C#的数组

    深入理解C#的数组

    本篇文章主要介绍了C#的数组,数组是一种数据结构,详细的介绍了数组的声明和访问等,有兴趣的可以了解一下。...

    佳园9492021-12-10
  • C#如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    如何使用C#将Tensorflow训练的.pb文件用在生产环境详解

    这篇文章主要给大家介绍了关于如何使用C#将Tensorflow训练的.pb文件用在生产环境的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴...

    bbird201811792022-03-05
  • C#C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    C#设计模式之Strategy策略模式解决007大破密码危机问题示例

    这篇文章主要介绍了C#设计模式之Strategy策略模式解决007大破密码危机问题,简单描述了策略模式的定义并结合加密解密算法实例分析了C#策略模式的具体使用...

    GhostRider10972022-01-21
  • C#三十分钟快速掌握C# 6.0知识点

    三十分钟快速掌握C# 6.0知识点

    这篇文章主要介绍了C# 6.0的相关知识点,文中介绍的非常详细,通过这篇文字可以让大家在三十分钟内快速的掌握C# 6.0,需要的朋友可以参考借鉴,下面来...

    雨夜潇湘8272021-12-28
  • C#C#微信公众号与订阅号接口开发示例代码

    C#微信公众号与订阅号接口开发示例代码

    这篇文章主要介绍了C#微信公众号与订阅号接口开发示例代码,结合实例形式简单分析了C#针对微信接口的调用与处理技巧,需要的朋友可以参考下...

    smartsmile20127762021-11-25
  • C#利用C#实现网络爬虫

    利用C#实现网络爬虫

    这篇文章主要介绍了利用C#实现网络爬虫,完整的介绍了C#实现网络爬虫详细过程,感兴趣的小伙伴们可以参考一下...

    C#教程网11852021-11-16
  • C#VS2012 程序打包部署图文详解

    VS2012 程序打包部署图文详解

    VS2012虽然没有集成打包工具,但它为我们提供了下载的端口,需要我们手动安装一个插件InstallShield。网上有很多第三方的打包工具,但为什么偏要使用微软...

    张信秀7712021-12-15
  • C#SQLite在C#中的安装与操作技巧

    SQLite在C#中的安装与操作技巧

    SQLite,是一款轻型的数据库,用于本地的数据储存。其优点有很多,下面通过本文给大家介绍SQLite在C#中的安装与操作技巧,感兴趣的的朋友参考下吧...

    蓝曈魅11162022-01-20