求一个多线程调用的写法,有100个任务,限定并发数为5

HG_Simon 2014-06-24 03:29:49
我现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个。
请问我要怎么写?
...全文
4645 26 打赏 收藏 转发到动态 举报
写回复
用AI写文章
26 条回复
切换为时间正序
请发表友善的回复…
发表回复
royler 2014-07-01
  • 打赏
  • 举报
回复
用队列,启动5个线程去获取里面的值,执行
越过越咸 2014-06-30
  • 打赏
  • 举报
回复
引用 24 楼 u012515900 的回复:
15楼老大很有耐心,还原写了实现代码,很感谢。 方案是OK的。 只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深, C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。 有哪位明白的兄弟能否给解个惑?
bu hui de ! da bu chu han zi
HG_Simon 2014-06-30
  • 打赏
  • 举报
回复
15楼老大很有耐心,还原写了实现代码,很感谢。 方案是OK的。 只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深, C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。 有哪位明白的兄弟能否给解个惑?
於黾 2014-06-26
  • 打赏
  • 举报
回复
引用 21 楼 lineages 的回复:
[quote=引用 7 楼 Z65443344 的回复:] [quote=引用 5 楼 u012515900 的回复:] 2楼3楼,请给个用法,谢谢。
早说嘛. 定义个线程池ThreadPool 然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了 然后把方法用线程池执行 跟用线程差不多的. 不过只适用于线程间执行的方法互相没有依赖的情况 因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制. 这样其实就用不到你说的100个线程了.你那100个线程白定义了.[/quote] 不要误导人家了! 线程池默认情况下,最小值是CPU的核心数,最大值则不确定,取决于系统和Framework版本 线程池不建议设置上下限,而且你还设置那么小,以为线程池是你专用的? FCL各种异步、TASK、PLINQ都要用到线程池,最终会出现严重的“饥饿”现象。[/quote] 好吧我错了.楼主请无视.
MR00009 2014-06-25
  • 打赏
  • 举报
回复
P哥难得一次不将大道理,而是实际性的给出解决方案。
暈哥 2014-06-25
  • 打赏
  • 举报
回复
引用 7 楼 Z65443344 的回复:
[quote=引用 5 楼 u012515900 的回复:] 2楼3楼,请给个用法,谢谢。
早说嘛. 定义个线程池ThreadPool 然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了 然后把方法用线程池执行 跟用线程差不多的. 不过只适用于线程间执行的方法互相没有依赖的情况 因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制. 这样其实就用不到你说的100个线程了.你那100个线程白定义了.[/quote] 不要误导人家了! 线程池默认情况下,最小值是CPU的核心数,最大值则不确定,取决于系统和Framework版本 线程池不建议设置上下限,而且你还设置那么小,以为线程池是你专用的? FCL各种异步、TASK、PLINQ都要用到线程池,最终会出现严重的“饥饿”现象。
baifucn 2014-06-25
  • 打赏
  • 举报
回复
15\16\17楼 这位大牛 经常碰见。。。
Sheldon_Lou 2014-06-25
  • 打赏
  • 举报
回复
引用 19 楼 xgp0009 的回复:
P哥难得一次不将大道理,而是实际性的给出解决方案。
这话有点
  • 打赏
  • 举报
回复
可以重构一次,把“结束”的时序调整得更合理:
    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();
            }
        }
    }
测试
            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();
  • 打赏
  • 举报
回复
比如说你使用10个线程进行断点续传,也是这个业务逻辑。你用不着在线程中写什么while语句,如果写了while语句,那么一定很乱。
  • 打赏
  • 举报
回复
如果TaskFactory可以做到,你可以使用它。不过需要测试一下是否真的能够保证你选择并发数,以及性能。 如果要了解原理,自己可以写一个。但是这并不需要什么while循环,你更不能简单粗暴地把1000个任务“平均”分配给5个线程。应该让线程中的过程执行完毕之后,自己去取下一个任务。 例如可以这样
    public class MyTaskList
    {
        public List<Action> Tasks = new List<Action>();

        public void Start()
        {
            for (var i = 0; i < 5; i++)
                StartAsync();
        }

        public void StartAsync()
        {
            lock (Tasks)
            {
                if (Tasks.Count > 0)
                {
                    var t = Tasks[Tasks.Count - 1];
                    Tasks.Remove(t);
                    ThreadPool.QueueUserWorkItem(h =>
                    {
                        t();
                        StartAsync();
                    });
                }
            }
        }
    }
然后你可以使用一个console程序测试
            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.Start();
            Console.WriteLine("________________________End");
这里,自动加入的100个测试任务,每一个运行时间都是不定的、随机的,这是其一。 其二就是,这里的 StartAsync 方法瞬间就结束了,根本不会阻塞,也不会等待什么 while 循环结束。
HG_Simon 2014-06-24
  • 打赏
  • 举报
回复
貌似很简单的,我一开始想复杂了,想用TaskFactory去做。
HG_Simon 2014-06-24
  • 打赏
  • 举报
回复
呵呵,用线程池可以搞定了,我的最终办法出来了。 这样

            var workList = new SafedQueue<string>();
            for (int i = 0; i < 100; i++)
            {
                workList.Enqueue(i.ToString());
            }
            for(int i = 0; i< 5; i++)
            {
                ThreadPool.QueueUserWorkItem(obj =>
                {
                    while (true)
                    {
                        var item = workList.Dequeue();
                        if (item == null)
                        {
                            break;
                        }
                        Thread.Sleep(1000);
                        Console.WriteLine(item);
                    }
                });
            }

  • 打赏
  • 举报
回复
开5个线程,每个线程每次只取一个任务进行处理,处理完毕累加计数器,接着取下一个任务,直到全部处理完
HG_Simon 2014-06-24
  • 打赏
  • 举报
回复
恩,自己写的话需要考虑到性能的东西就比较多,所以我还是倾向用.net提供的方法 。 但是ThreadPool不能实例化,如果要设置最大线程数也是全局的,就会影响到其他地方。 另外,我发现设置ThreadPool的线程最大线程数貌似没用。
  • 打赏
  • 举报
回复
线程池托管的,怎么就不建议用了 开5个线程去处理
volatile int number;
for(int i = 0; i< 5; i++)
{
       ThreadPool.QueueUserWorkItem(obj =>
       {
            while(number < 100)
            {
                  doSthing(number);
                  number++;
            }
       }
}
tcmakebest 2014-06-24
  • 打赏
  • 举报
回复
并发数不需要控制啊,你开几个线程就是并发几个,让线程自己取任务循环运行,注意任务列表的同步就行.
於黾 2014-06-24
  • 打赏
  • 举报
回复
是我不好,把100个任务看成100个线程同时只让5个执行,抱歉抱歉
於黾 2014-06-24
  • 打赏
  • 举报
回复
引用 5 楼 u012515900 的回复:
2楼3楼,请给个用法,谢谢。
早说嘛. 定义个线程池ThreadPool 然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了 然后把方法用线程池执行 跟用线程差不多的. 不过只适用于线程间执行的方法互相没有依赖的情况 因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制. 这样其实就用不到你说的100个线程了.你那100个线程白定义了.
失落的神庙 2014-06-24
  • 打赏
  • 举报
回复
任务全部添加进去 设置线程最大数 即可
加载更多回复(5)

110,535

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧