我正在编写一个应用程序,其中大部分工作由后台线程完成(10 - 500个线程)。如何将暂停/恢复功能添加到应用程序?
我想添加暂停/恢复功能。
之前,你可以用Thread.Suspend和Thread.Resume来做到这一点。但是这些功能现在被认为已经过时。
有什么可以让我在平等的情况下做同样的事吗?
我正在用c编写软件#
我正在编写一个应用程序,其中大部分工作由后台线程完成(10 - 500个线程)。如何将暂停/恢复功能添加到应用程序?
我想添加暂停/恢复功能。
之前,你可以用Thread.Suspend和Thread.Resume来做到这一点。但是这些功能现在被认为已经过时。
有什么可以让我在平等的情况下做同样的事吗?
我正在用c编写软件#
已经用C#编写高性能的爬虫,我可以与一些权威机构,明确管理数十或数百个线程是不是最好的方式去说。它可以做到(我做到了),但是它极端痛苦。
这就是说。 。 。
如果你的应用程序是用我的思维方式,那么每个线程做这样的事情:
while (!Shutdown)
{
// get next url to crawl from somewhere
// download the data from that url
// do something with the data
}
暂停下载的线程是很容易的。我会建议制作两个ManualResetEvent
实例:一个用于继续,另一个用于关闭。这些是static
使得所有履带线程可以访问它们:
static ManualResetEvent ShutdownEvent = new ManualResetEvent(false);
static ManualResetEvent ContinueEvent = new ManualResetEvent(true);
然后,每个线程在一个循环中使用WaitAny
:
WaitHandle[] handles = new WaitHandle[] { ShutdownEvent, ContinueEvent };
while (true)
{
int handle = WaitHandle.WaitAny(handles); // wait for one of the events
if (handle == -1 || handle >= handles.Length)
{
throw new ApplicationException();
}
if (handles[handle] = ShutdownEvent)
break; // shutdown was signaled
if (handles[handle] == ContinueEvent)
{
// download the next page and do something with the data
}
}
注意,当我所定义的handles
阵列,我指定ShutdownEvent
第一。原因是如果多个项目被发信号通知,WaitAny
返回与发信号对象相对应的最低索引。如果数组以其他顺序填充,那么如果不先暂停,则无法关闭。
现在,如果您希望线程关闭,请致电ShutdownEvent.Set
。如果您希望线程暂停,请致电ContinueEvent.Reset
当您希望线程恢复时,请致电ContinueEvent.Set
。
在下载过程中暂停有点困难。这是可能的,但问题是,如果您暂停太久,服务器可能会超时。然后,您必须从头开始重新下载,或者如果服务器和您的代码支持它,请从您停止的位置重新开始下载。这两个选项都很痛苦,所以我不会建议在下载过程中暂停。
你的应用做什么?
500个线程太多 - 这是1/2 GB的承诺内存仅用于堆栈。然后你有所有的上下文切换。
好,你想摆脱Suspend
和Resume
调用,但我建议你先看看你的架构 - 你可以移动到APM方法(BeginXXX/EndXXX)?
这是一个网络应用程序,它从网上下载信息。因为它大部分时间都在等待响应,多线程对我来说似乎是个好主意。如果你知道更好的方法来完成它,请告诉我 –
作为一个告诫,我要说什么:不清楚你的应用程序做什么;有许多使用线程池线程的简单方法,例如TPL,后台工作者等。
但是,如果您有创建的线程(而不是线程池)并且希望它们进行通信,则使用Monitor.Wait和Monitor。具有布尔阻塞条件的脉冲。
e.g:
bool _isPaused;
void DoWork()
{
while (true)
{
lock (_locker)
{
while (_isPaused) Monitor.Wait(_locker);
// your worker code here
}
}
}
//
void UnPause()
{
lock (_locker)
{
_isPaused=false;
Monitor.PulseAll(_locker);
}
}
不是真的。暂停/恢复真的很简单,直到他们崩溃你的应用程序,例如。通过暂停内存管理器或文件系统被锁定的线程:(
通常的,稍微复杂的方法是在你的线程中找到你可以等待的地方,在你的情况下,我猜测最的线程通常在某些IO调用上被阻塞,因此被“挂起”,因此在读取后执行“暂停”的好地方是为了捕获读取返回的线程。可以通过检查@Andrey建议的全局布尔'isRunning'标志来实现实际挂起,如果需要挂起,则阻止全局ManualResetEvent挂起,清除事件,然后清除标志。然后事件
如果使用全局变量会让你感到恶心,那么你可以传入一个包含标志,事件和'suspend(),'resume()'和'checkForSuspend()'方法的类的公共实例。
RGDS, 马丁
如果您需要任何有用的回应,您需要提供更多信息。这些线程在做什么?他们是如何开始的?他们在什么条件下被“暂停?”没有更多的信息,回答这个问题是不可能的。 –
一个进程中的500个线程是一个*巨大数量的线程,特别是如果其中一堆线程大部分时间处于睡眠状态。我的建议是重新设计你的架构,以便不使用比机器中的处理器更多的线程。线程在C#中非常“重”;你应该创造完成工作所需的绝对最低限度。你在做什么,你正在创造这么多的线程? –
这是一个网络爬行应用程序。每个线程花费大部分时间等待来自某个Web服务器的响应,所有线程都在相同的地方启动,并且应该在用户按下“暂停”按钮时暂停。该应用程序通常需要700m-2G的内存,除非有更好的方法来做到这一点,否则我可以接受。即使在500个线程下,应用程序通常也只有不到30%的单个CPU运行 –