C# 多线程模型
C# Multithreading Model
我有一个 c# 单线程应用程序,目前正致力于通过使用线程池使其成为多线程。我一直在决定哪种模型可以解决我的问题。
这是我目前的情况
While(1)
{
do_sometask();
wait(time);
}
这几乎永远重复。新场景有多个线程执行上述操作。我可以根据我必须执行的任务生成线程数来轻松实现它,所有线程都执行一些任务并永远等待。
这里的问题是我可能不知道任务的数量,所以我不能盲目地生成 500 个线程。我考虑过使用线程池,但是因为几乎每个线程都永远循环并且永远不会被释放用于队列中的新任务,所以我不确定要使用哪个其他模型。
我正在寻找一个想法或解决方案,我可以打破线程中的循环并释放它而不是等待,但在等待之后返回并恢复相同的任务(当时间过去时,使用一些东西就像执行最后一个任务时的 timer/checking 时间戳)。
有了这个,我可以使用有限数量的线程(比如在线程池中)并处理在旧线程等待期间(虚拟)进入的任务。
非常感谢任何帮助。
如果你只有一堆周期性发生的事情,听起来你想要的就是一堆计时器。为每个任务创建一个计时器,在适当的时候触发。因此,如果您有两个不同的任务:
using System.Threading;
// Task1 happens once per minute
Timer task1Timer = new Timer(
s => DoTask1(),
null,
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1));
// Task2 happens once every 47 seconds
Timer task2Timer = new Timer(
s => DoTask2(),
null,
TimeSpan.FromSeconds(47),
TimeSpan.FromSeconds(47);
计时器是一个非常轻量级的对象,因此拥有一大堆它们并不是真正的问题。计时器在触发时仅占用 CPU 资源。回调方法将在池线程上执行。
存在 1 个潜在问题。如果你有很多定时器都具有相同的周期,那么回调将同时被调用。线程池 应该 通过限制并发任务的数量来优雅地处理这个问题,但我不能肯定地说。但是,如果您的等待时间是交错的,这会很有效。
如果您的等待时间很短(不到一秒),那么您可能需要一种不同的技术。如果需要,我会详细说明。
采用这种设计,您在任何时候都只有一个线程被阻塞。
有一个线程(主线程)等待并发阻塞集合,例如BlockingCollection。此线程将被对 TryTake
的调用阻塞,直到将某些东西放入集合中,或者在通过超时传递到调用中经过一定时间后(稍后详细介绍)。
一旦解除阻塞,它可能有一个工作单元要处理。它检查是否有一个(即 TryTake
调用没有超时),然后是否有能力执行这项工作,如果有,则排队一个线程(池、任务或 whatevs)为工作服务。然后这个主线程返回到阻塞集合并尝试进行另一个工作单元。循环继续。
当一个工作单元开始时,它会被记录下来,以便主线程可以看到有多少线程在工作。一旦这个单元完成,符号将被删除。然后线程被释放。
你想使用超时,这样如果判断同时运行操作过多,你就可以在设定的时间段内重新评估。否则,该工作单元将位于阻塞集合中,直到添加新单元为止,这不是最优的。
此实例的外部用户只需将新工作单元放入集合中即可对它们进行排队。
您可以使用取消标记在需要关闭操作时立即取消阻塞线程。让工作人员操作也接受取消令牌,以便它们可以在关闭时停止。
我可以在线程池的帮助下实现它,并且在将任务添加到线程池队列之前检查最后一个 activity 任务的条件很少。
我有一个 c# 单线程应用程序,目前正致力于通过使用线程池使其成为多线程。我一直在决定哪种模型可以解决我的问题。
这是我目前的情况
While(1)
{
do_sometask();
wait(time);
}
这几乎永远重复。新场景有多个线程执行上述操作。我可以根据我必须执行的任务生成线程数来轻松实现它,所有线程都执行一些任务并永远等待。
这里的问题是我可能不知道任务的数量,所以我不能盲目地生成 500 个线程。我考虑过使用线程池,但是因为几乎每个线程都永远循环并且永远不会被释放用于队列中的新任务,所以我不确定要使用哪个其他模型。
我正在寻找一个想法或解决方案,我可以打破线程中的循环并释放它而不是等待,但在等待之后返回并恢复相同的任务(当时间过去时,使用一些东西就像执行最后一个任务时的 timer/checking 时间戳)。
有了这个,我可以使用有限数量的线程(比如在线程池中)并处理在旧线程等待期间(虚拟)进入的任务。
非常感谢任何帮助。
如果你只有一堆周期性发生的事情,听起来你想要的就是一堆计时器。为每个任务创建一个计时器,在适当的时候触发。因此,如果您有两个不同的任务:
using System.Threading;
// Task1 happens once per minute
Timer task1Timer = new Timer(
s => DoTask1(),
null,
TimeSpan.FromMinutes(1),
TimeSpan.FromMinutes(1));
// Task2 happens once every 47 seconds
Timer task2Timer = new Timer(
s => DoTask2(),
null,
TimeSpan.FromSeconds(47),
TimeSpan.FromSeconds(47);
计时器是一个非常轻量级的对象,因此拥有一大堆它们并不是真正的问题。计时器在触发时仅占用 CPU 资源。回调方法将在池线程上执行。
存在 1 个潜在问题。如果你有很多定时器都具有相同的周期,那么回调将同时被调用。线程池 应该 通过限制并发任务的数量来优雅地处理这个问题,但我不能肯定地说。但是,如果您的等待时间是交错的,这会很有效。
如果您的等待时间很短(不到一秒),那么您可能需要一种不同的技术。如果需要,我会详细说明。
采用这种设计,您在任何时候都只有一个线程被阻塞。
有一个线程(主线程)等待并发阻塞集合,例如BlockingCollection。此线程将被对 TryTake
的调用阻塞,直到将某些东西放入集合中,或者在通过超时传递到调用中经过一定时间后(稍后详细介绍)。
一旦解除阻塞,它可能有一个工作单元要处理。它检查是否有一个(即 TryTake
调用没有超时),然后是否有能力执行这项工作,如果有,则排队一个线程(池、任务或 whatevs)为工作服务。然后这个主线程返回到阻塞集合并尝试进行另一个工作单元。循环继续。
当一个工作单元开始时,它会被记录下来,以便主线程可以看到有多少线程在工作。一旦这个单元完成,符号将被删除。然后线程被释放。
你想使用超时,这样如果判断同时运行操作过多,你就可以在设定的时间段内重新评估。否则,该工作单元将位于阻塞集合中,直到添加新单元为止,这不是最优的。
此实例的外部用户只需将新工作单元放入集合中即可对它们进行排队。
您可以使用取消标记在需要关闭操作时立即取消阻塞线程。让工作人员操作也接受取消令牌,以便它们可以在关闭时停止。
我可以在线程池的帮助下实现它,并且在将任务添加到线程池队列之前检查最后一个 activity 任务的条件很少。