思路来源:http://bbs.csdn.NET/topics/390819824,引用该页面某网友提供的方法。

题目:我现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个。

原理:初始启用5个线程,然后让线程中的过程执行完毕之后,自己去取下一个任务,启动下一个线程。

  1. public class MyTaskList
  2. {
  3. public List<Action> Tasks = new List<Action>();
  4. public void Start()
  5. {
  6. for (var i = 0; i < 5; i++)
  7. StartAsync();
  8. }
  9. public event Action Completed;
  10. public void StartAsync()
  11. {
  12. lock (Tasks)
  13. {
  14. if (Tasks.Count > 0)
  15. {
  16. var t = Tasks[Tasks.Count - 1];
  17. Tasks.Remove(t);
  18. ThreadPool.QueueUserWorkItem(h =>
  19. {
  20. t();
  21. StartAsync();
  22. });
  23. }
  24. else if (Completed != null)
  25. Completed();
  26. }
  27. }
  28. }
    public class MyTaskList
{
public List<Action> Tasks = new List<Action>(); public void Start()
{
for (var i = 0; i < 5; i++)
StartAsync();
} public event Action Completed; public void StartAsync()
{
lock (Tasks)
{
if (Tasks.Count > 0)
{
var t = Tasks[Tasks.Count - 1];
Tasks.Remove(t);
ThreadPool.QueueUserWorkItem(h =>
{
t();
StartAsync();
});
}
else if (Completed != null)
Completed();
}
}
}

调用方式:

1,自动加入的100个测试任务,每一个运行时间都是不定的、随机的。

2,这里的 StartAsync 方法瞬间就结束了,根本不会阻塞,也不会等待什么 while 循环结束

  1. var rnd = new Random();
  2. var lst = new MyTaskList();
  3. for (var i = 0; i < 100; i++)
  4. {
  5. var s = rnd.Next(10);
  6. var j = i;
  7. var 测试任务 = new Action(() =>
  8. {
  9. Console.WriteLine(string.Format("第{0}个任务(用时{1}秒)已经开始", j, s));
  10. Thread.Sleep(s * 1000);
  11. Console.WriteLine(string.Format("第{0}个任务(用时{1}秒)已经结束", j, s));
  12. });
  13. lst.Tasks.Add(测试任务);
  14. }
  15. lst.Completed += () => Console.WriteLine("____________________没有更多的任务了!");
  16. lst.Start();
            var rnd = new Random();
var lst = new MyTaskList();
for (var i = 0; i < 100; i++)
{
var s = rnd.Next(10);
var j = i;
var 测试任务 = new Action(() =>
{
Console.WriteLine(string.Format("第{0}个任务(用时{1}秒)已经开始", j, s));
Thread.Sleep(s * 1000);
Console.WriteLine(string.Format("第{0}个任务(用时{1}秒)已经结束", j, s));
});
lst.Tasks.Add(测试任务);
}
lst.Completed += () => Console.WriteLine("____________________没有更多的任务了!");
lst.Start();

自己使用到程序中,自定义最大线程数,然后循环启用最大线程数个线程执行任务,等待有线程完成,退出本次运行方法和线程前,再次调用启用线程方法调用下一个线程,依次循环,直至完成:

  1. AutoResetEvent[] waitEnents = new AutoResetEvent[n_max_thread];
  2. for (int i = 0; i < n_max_thread; i++)
  3. {
  4. calcState.wait_event = waitEnents[i] = new AutoResetEvent(false);
  5. StartAsync(calcState);
  6. }
  7. AutoResetEvent.WaitAll(waitEnents);
  8. private static void StartAsync(CalcState calcState)
  9. {
  10. lock (calcState.locker_ListFormula)
  11. {
  12. if (calcState.lstFormula.Count > 0)
  13. {
  14. calcState.formulaAttr = calcState.lstFormula.ElementAt(calcState.lstFormula.Count - 1).Value;
  15. calcState.lstFormula.Remove(calcState.lstFormula.ElementAt(calcState.lstFormula.Count - 1).Key);
  16. ThreadPool.QueueUserWorkItem(new WaitCallback(ExecAsync), calcState);
  17. }
  18. else
  19. {
  20. calcState.wait_event.Set();
  21. }
  22. }
  23. }
  24. private static void ExecAsync(object obj)
  25. {
  26. CalcState calcState = obj as CalcState;
  27. startCalcFormula(calcState);
  28. //递归处理下一个公式
  29. StartAsync(calcState);
  30. }
  31. private static void startCalcFormula(CalcState calcState)
  32. {
  33. }
        AutoResetEvent[] waitEnents = new AutoResetEvent[n_max_thread];
for (int i = 0; i < n_max_thread; i++)
{
calcState.wait_event = waitEnents[i] = new AutoResetEvent(false); StartAsync(calcState);
} AutoResetEvent.WaitAll(waitEnents); private static void StartAsync(CalcState calcState)
{
lock (calcState.locker_ListFormula)
{
if (calcState.lstFormula.Count > 0)
{
calcState.formulaAttr = calcState.lstFormula.ElementAt(calcState.lstFormula.Count - 1).Value;
calcState.lstFormula.Remove(calcState.lstFormula.ElementAt(calcState.lstFormula.Count - 1).Key);
ThreadPool.QueueUserWorkItem(new WaitCallback(ExecAsync), calcState);
}
else
{
calcState.wait_event.Set();
}
} } private static void ExecAsync(object obj)
{
CalcState calcState = obj as CalcState;
startCalcFormula(calcState);
//递归处理下一个公式
StartAsync(calcState);
} private static void startCalcFormula(CalcState calcState)
{ }

C# 执行固定个数任务自行控制进入线程池的线程数量,多任务同时但是并发数据限定的更多相关文章

  1. 由浅入深理解Java线程池及线程池的如何使用

    前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担.线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory ...

  2. Java多线程、线程池和线程安全整理

    多线程 1.1      多线程介绍 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 1.2      Thread类 通 ...

  3. Java多线程系列 JUC线程池03 线程池原理解析(二)

    转载  http://www.cnblogs.com/skywang12345/p/3509954.html  http://www.cnblogs.com/skywang12345/p/351294 ...

  4. Java多线程系列 JUC线程池02 线程池原理解析(一)

    转载  http://www.cnblogs.com/skywang12345/p/3509960.html ; http://www.cnblogs.com/skywang12345/p/35099 ...

  5. Java多线程系列 JUC线程池01 线程池框架

    转载  http://www.cnblogs.com/skywang12345/p/3509903.html 为什么引入Executor线程池框架 new Thread()的缺点 1. 每次new T ...

  6. 异步线程编程,线程池,线程组,后面涉及ThreadLocal在理解

    join模拟订单 package com.future.demo.future; /** * * * @author Administrator * */ public class NormalThr ...

  7. java并发编程(十五)----(线程池)java线程池简介

    好的软件设计不建议手动创建和销毁线程.线程的创建和销毁是非常耗 CPU 和内存的,因为这需要 JVM 和操作系统的参与.64位 JVM 默认线程栈是大小1 MB.这就是为什么说在请求频繁时为每个小的请 ...

  8. 多线程、线程池、线程创建、Thread

    转载自https://www.cnblogs.com/jmsjh/p/7762034.html 多线程 1.1 多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行 ...

  9. java 线程池(线程的复用)

    一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池.使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动 ...

随机推荐

  1. 函数防抖与函数节流 封装好的debounce和throttle函数

    /** * 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行 * * @param {function} func 传入函数,最后一个参数是额外增加的this对象,. ...

  2. [HDU4787]GRE Words Revenge 解题报告

    这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...

  3. 浅谈Tarjan算法及思想

    在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大强连通子图,称为强连 ...

  4. loj2542 「PKUWC2018」随机游走 【树形dp + 状压dp + 数学】

    题目链接 loj2542 题解 设\(f[i][S]\)表示从\(i\)节点出发,走完\(S\)集合中的点的期望步数 记\(de[i]\)为\(i\)的度数,\(E\)为边集,我们很容易写出状态转移方 ...

  5. 【bzoj2438】 中山市选2011—杀人游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=2438 (题目链接) 题意 n个点的有向图,其中有一个是杀手,每个人成为杀手的概率相同.警察询问一个人 ...

  6. struts2练习时犯的错误(2016年11月4日)

    1.Tomcat启动时报错 严重: 文档无效: 找不到语法. at (null:3:8) org.xml.sax.SAXParseException; systemId: file:/F:/Progr ...

  7. oracle 11g 压缩数据文件

    通过以下语句直接分析出每个数据库文件可压缩量 select a.file#, a.name, a.bytes CurrentMB, ceil(HWM ResizeTo, (a.bytes Releas ...

  8. go语言从零学起(三) -- chat实现的思考

    要通过go实现一个应用场景: 1 建立一个websocket服务 2 维护在线用户的链接 3 推送消息和接受用户的操作 列出需求,很显然的想到了chat模型.于是研究了revel框架提供的sample ...

  9. P1792 [国家集训队]种树

    P1792 [国家集训队]种树 题目描述 A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树. 园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n.并且每 ...

  10. day14 多态与抽象

    多态:相同的行为,不同的实现. 多态分为:静态多态和动态多态. 静态多态:在编译期即确定方法的实现和效果.——使用重载实现 动态多态:运行后才能确定方法的实现和执行效果.——使用动态绑定和重写实现 动 ...