请问我要怎么写?
26 个解决方案
#1
baidu,google一下线程同步,你能找到很多解决方案
最简单的办法是定义个静态全局变量当做红绿灯
线程开始时判断它是否大于4,不大于4就++并且执行代码,执行完毕--
如果大于4,做个while等待,等待时间可以是个随机数
最简单的办法是定义个静态全局变量当做红绿灯
线程开始时判断它是否大于4,不大于4就++并且执行代码,执行完毕--
如果大于4,做个while等待,等待时间可以是个随机数
#2
话说线程池可以
不过不建议用。
不过不建议用。
#3
4.0开始的Task处理这个问题很轻松
#4
楼上兄弟,这个貌似不需要用到线程同步的吧。
我自己写个简单的类就完成了需求了。
只是想使用系统的线程池来完成。
我自己写个简单的类就完成了需求了。
只是想使用系统的线程池来完成。
public class LimitedTaskFactoryEx
{
private readonly int _maxThreadCount = 5;
public LimitedTaskFactoryEx(int maxThreadCount)
{
_maxThreadCount = maxThreadCount;
Start();
}
private readonly SafedQueue<Action> _actionQueue = new SafedQueue<Action>();
public void StartNew(Action action)
{
_actionQueue.Enqueue(action);
}
private void Start()
{
for (int i = 0; i < _maxThreadCount; i++)
{
var thread = new Thread(new ThreadStart(InternalRun));
thread.Start();
}
}
private void InternalRun()
{
while (true)
{
var action = _actionQueue.Dequeue();
if (action != null)
{
action();
}
else
{
Thread.Sleep(30);
}
Console.WriteLine(string.Format("Index: {0}, TaskId: {1}, ThreadId: {2}.", 1, Task.CurrentId,
Thread.CurrentThread.ManagedThreadId));
}
}
}
#5
2楼3楼,请给个用法,谢谢。
#6
任务全部添加进去
设置线程最大数 即可
#7
早说嘛.
定义个线程池ThreadPool
然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了
然后把方法用线程池执行
跟用线程差不多的.
不过只适用于线程间执行的方法互相没有依赖的情况
因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制.
这样其实就用不到你说的100个线程了.你那100个线程白定义了.
#8
是我不好,把100个任务看成100个线程同时只让5个执行,抱歉抱歉
#9
并发数不需要控制啊,你开几个线程就是并发几个,让线程自己取任务循环运行,注意任务列表的同步就行.
#10
线程池托管的,怎么就不建议用了
开5个线程去处理
开5个线程去处理
volatile int number;
for(int i = 0; i< 5; i++)
{
ThreadPool.QueueUserWorkItem(obj =>
{
while(number < 100)
{
doSthing(number);
number++;
}
}
}
#11
恩,自己写的话需要考虑到性能的东西就比较多,所以我还是倾向用.net提供的方法 。
但是ThreadPool不能实例化,如果要设置最大线程数也是全局的,就会影响到其他地方。
另外,我发现设置ThreadPool的线程最大线程数貌似没用。
但是ThreadPool不能实例化,如果要设置最大线程数也是全局的,就会影响到其他地方。
另外,我发现设置ThreadPool的线程最大线程数貌似没用。
#12
开5个线程,每个线程每次只取一个任务进行处理,处理完毕累加计数器,接着取下一个任务,直到全部处理完
#13
呵呵,用线程池可以搞定了,我的最终办法出来了。
这样
这样
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);
}
});
}
#14
貌似很简单的,我一开始想复杂了,想用TaskFactory去做。
#15
如果TaskFactory可以做到,你可以使用它。不过需要测试一下是否真的能够保证你选择并发数,以及性能。
如果要了解原理,自己可以写一个。但是这并不需要什么while循环,你更不能简单粗暴地把1000个任务“平均”分配给5个线程。应该让线程中的过程执行完毕之后,自己去取下一个任务。
例如可以这样
然后你可以使用一个console程序测试
这里,自动加入的100个测试任务,每一个运行时间都是不定的、随机的,这是其一。
其二就是,这里的 StartAsync 方法瞬间就结束了,根本不会阻塞,也不会等待什么 while 循环结束。
如果要了解原理,自己可以写一个。但是这并不需要什么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 循环结束。
#16
比如说你使用10个线程进行断点续传,也是这个业务逻辑。你用不着在线程中写什么while语句,如果写了while语句,那么一定很乱。
#17
可以重构一次,把“结束”的时序调整得更合理:
测试
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();
#18
15\16\17楼 这位大牛 经常碰见。。。
#19
P哥难得一次不将大道理,而是实际性的给出解决方案。
#20
这话有点
#21
不要误导人家了!
线程池默认情况下,最小值是CPU的核心数,最大值则不确定,取决于系统和Framework版本
线程池不建议设置上下限,而且你还设置那么小,以为线程池是你专用的?
FCL各种异步、TASK、PLINQ都要用到线程池,最终会出现严重的“饥饿”现象。
#22
#23
2楼3楼,请给个用法,谢谢。
早说嘛.
定义个线程池ThreadPool
然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了
然后把方法用线程池执行
跟用线程差不多的.
不过只适用于线程间执行的方法互相没有依赖的情况
因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制.
这样其实就用不到你说的100个线程了.你那100个线程白定义了.
不要误导人家了!
线程池默认情况下,最小值是CPU的核心数,最大值则不确定,取决于系统和Framework版本
线程池不建议设置上下限,而且你还设置那么小,以为线程池是你专用的?
FCL各种异步、TASK、PLINQ都要用到线程池,最终会出现严重的“饥饿”现象。
好吧我错了.楼主请无视.
#24
15楼老大很有耐心,还原写了实现代码,很感谢。
方案是OK的。
只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深,
C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。
有哪位明白的兄弟能否给解个惑?
方案是OK的。
只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深,
C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。
有哪位明白的兄弟能否给解个惑?
#25
15楼老大很有耐心,还原写了实现代码,很感谢。
方案是OK的。
只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深,
C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。
有哪位明白的兄弟能否给解个惑?
bu hui de ! da bu chu han zi
#26
用队列,启动5个线程去获取里面的值,执行
#1
baidu,google一下线程同步,你能找到很多解决方案
最简单的办法是定义个静态全局变量当做红绿灯
线程开始时判断它是否大于4,不大于4就++并且执行代码,执行完毕--
如果大于4,做个while等待,等待时间可以是个随机数
最简单的办法是定义个静态全局变量当做红绿灯
线程开始时判断它是否大于4,不大于4就++并且执行代码,执行完毕--
如果大于4,做个while等待,等待时间可以是个随机数
#2
话说线程池可以
不过不建议用。
不过不建议用。
#3
4.0开始的Task处理这个问题很轻松
#4
楼上兄弟,这个貌似不需要用到线程同步的吧。
我自己写个简单的类就完成了需求了。
只是想使用系统的线程池来完成。
我自己写个简单的类就完成了需求了。
只是想使用系统的线程池来完成。
public class LimitedTaskFactoryEx
{
private readonly int _maxThreadCount = 5;
public LimitedTaskFactoryEx(int maxThreadCount)
{
_maxThreadCount = maxThreadCount;
Start();
}
private readonly SafedQueue<Action> _actionQueue = new SafedQueue<Action>();
public void StartNew(Action action)
{
_actionQueue.Enqueue(action);
}
private void Start()
{
for (int i = 0; i < _maxThreadCount; i++)
{
var thread = new Thread(new ThreadStart(InternalRun));
thread.Start();
}
}
private void InternalRun()
{
while (true)
{
var action = _actionQueue.Dequeue();
if (action != null)
{
action();
}
else
{
Thread.Sleep(30);
}
Console.WriteLine(string.Format("Index: {0}, TaskId: {1}, ThreadId: {2}.", 1, Task.CurrentId,
Thread.CurrentThread.ManagedThreadId));
}
}
}
#5
2楼3楼,请给个用法,谢谢。
#6
任务全部添加进去
设置线程最大数 即可
#7
2楼3楼,请给个用法,谢谢。
早说嘛.
定义个线程池ThreadPool
然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了
然后把方法用线程池执行
跟用线程差不多的.
不过只适用于线程间执行的方法互相没有依赖的情况
因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制.
这样其实就用不到你说的100个线程了.你那100个线程白定义了.
#8
是我不好,把100个任务看成100个线程同时只让5个执行,抱歉抱歉
#9
并发数不需要控制啊,你开几个线程就是并发几个,让线程自己取任务循环运行,注意任务列表的同步就行.
#10
线程池托管的,怎么就不建议用了
开5个线程去处理
开5个线程去处理
volatile int number;
for(int i = 0; i< 5; i++)
{
ThreadPool.QueueUserWorkItem(obj =>
{
while(number < 100)
{
doSthing(number);
number++;
}
}
}
#11
恩,自己写的话需要考虑到性能的东西就比较多,所以我还是倾向用.net提供的方法 。
但是ThreadPool不能实例化,如果要设置最大线程数也是全局的,就会影响到其他地方。
另外,我发现设置ThreadPool的线程最大线程数貌似没用。
但是ThreadPool不能实例化,如果要设置最大线程数也是全局的,就会影响到其他地方。
另外,我发现设置ThreadPool的线程最大线程数貌似没用。
#12
开5个线程,每个线程每次只取一个任务进行处理,处理完毕累加计数器,接着取下一个任务,直到全部处理完
#13
呵呵,用线程池可以搞定了,我的最终办法出来了。
这样
这样
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);
}
});
}
#14
貌似很简单的,我一开始想复杂了,想用TaskFactory去做。
#15
如果TaskFactory可以做到,你可以使用它。不过需要测试一下是否真的能够保证你选择并发数,以及性能。
如果要了解原理,自己可以写一个。但是这并不需要什么while循环,你更不能简单粗暴地把1000个任务“平均”分配给5个线程。应该让线程中的过程执行完毕之后,自己去取下一个任务。
例如可以这样
然后你可以使用一个console程序测试
这里,自动加入的100个测试任务,每一个运行时间都是不定的、随机的,这是其一。
其二就是,这里的 StartAsync 方法瞬间就结束了,根本不会阻塞,也不会等待什么 while 循环结束。
如果要了解原理,自己可以写一个。但是这并不需要什么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 循环结束。
#16
比如说你使用10个线程进行断点续传,也是这个业务逻辑。你用不着在线程中写什么while语句,如果写了while语句,那么一定很乱。
#17
可以重构一次,把“结束”的时序调整得更合理:
测试
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();
#18
15\16\17楼 这位大牛 经常碰见。。。
#19
P哥难得一次不将大道理,而是实际性的给出解决方案。
#20
P哥难得一次不将大道理,而是实际性的给出解决方案。
这话有点
#21
2楼3楼,请给个用法,谢谢。
早说嘛.
定义个线程池ThreadPool
然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了
然后把方法用线程池执行
跟用线程差不多的.
不过只适用于线程间执行的方法互相没有依赖的情况
因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制.
这样其实就用不到你说的100个线程了.你那100个线程白定义了.
不要误导人家了!
线程池默认情况下,最小值是CPU的核心数,最大值则不确定,取决于系统和Framework版本
线程池不建议设置上下限,而且你还设置那么小,以为线程池是你专用的?
FCL各种异步、TASK、PLINQ都要用到线程池,最终会出现严重的“饥饿”现象。
#22
#23
2楼3楼,请给个用法,谢谢。
早说嘛.
定义个线程池ThreadPool
然后可以指定最小线程数量和最大线程数量,你分别定义成0和5就行了
然后把方法用线程池执行
跟用线程差不多的.
不过只适用于线程间执行的方法互相没有依赖的情况
因为线程池具体如何调用线程的过程不受控制,执行顺序也不受控制.
这样其实就用不到你说的100个线程了.你那100个线程白定义了.
不要误导人家了!
线程池默认情况下,最小值是CPU的核心数,最大值则不确定,取决于系统和Framework版本
线程池不建议设置上下限,而且你还设置那么小,以为线程池是你专用的?
FCL各种异步、TASK、PLINQ都要用到线程池,最终会出现严重的“饥饿”现象。
好吧我错了.楼主请无视.
#24
15楼老大很有耐心,还原写了实现代码,很感谢。
方案是OK的。
只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深,
C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。
有哪位明白的兄弟能否给解个惑?
方案是OK的。
只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深,
C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。
有哪位明白的兄弟能否给解个惑?
#25
15楼老大很有耐心,还原写了实现代码,很感谢。
方案是OK的。
只是有一个小的疑问,如果任务比较多的话,这样的递规调用会不会导致堆栈太深,
C#我还没有学得那么深入,也不知道堆栈太深会不会引发什么问题。
有哪位明白的兄弟能否给解个惑?
bu hui de ! da bu chu han zi
#26
用队列,启动5个线程去获取里面的值,执行