请教一个关于线程池的问题

绿色夹克衫 2010-01-19 11:31:31
关于ThreadPool,许多资料中都有这么一条建议,就是:

当你的任务需要执行很长时间时,不适宜用ThreadPool。

但这个时间究竟是多长?大部分网上的内容都没有给个准数,个别资料里说是几秒钟。我觉得这个数也未必准确。
因为这些资料里都没有讲清楚2个问题

1、为什么任务需要执行很长时间的情况不宜使用ThreadPool?
2、如何有效地测试分析这个时间的阀值?
3、什么类型的长时任务不宜用ThreadPool?(Cpu占用时间长?IO占用时间长?网络连接时间长?......)我感觉应该可以区别对待。

就以上几个问题,特向各位高手请教!
...全文
314 31 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
libinfei8848 2010-04-22
  • 打赏
  • 举报
回复
线程执行时间过长会造成cpu占用率过高的,会引起客户的恐慌的。。。
j_f0001 2010-01-20
  • 打赏
  • 举报
回复
首先给你讲讲同步与异步 阻塞与非阻塞模式
在基于.NET的网络服务端的开发中,我们用到和听到的最多的恐怕就是异步Socket了。异步Socket的性能比同步高出很多,但是编写代码比较复杂。因此异步Socket也是网络上讨论比较多的话题。

今天,我们就来讨论一下如何用异步Socket开发网络应用。在此之前我们先讨论两个问题。

一、异步Socket是如何工作的:

那异步Socket是如何工作的呢?我以接收一条消息来说明这个问题。首先,程序向系统投递一个接收数据的请求,并为其指定一个数据缓冲区和回调函数,回调函数用来指示当数据到达后将如何处理,然后我们的程序继续执行下去,当有数据到达的时候,系统将数据读入缓冲区,并执行回调函数,处理这条消息。我们并不需要关心这条消息何时到达。

二、什么情况下我们用异步Socket:

有些人认为,异步Socket的性能比同步Socket的性能高很多,应该在各种环境下都用异步Socket,其实不然。在某些环境下面。异步反到比同步的性能低,那么在哪些情况下会这样呢?

1、 客户端Socket。

2、 服务端连接数比较少。

3、 连接数很多,但都是短连接。

在这些环境下,我们用同步Socket不但可以简化代码,而且性能并不会比异步Socket低。但在服务端连接比较多而且是长连接的情况下,我们就要使用异步Socket。

现在我们来看看如何用异步Socket编程。

首先,我们要建立一个Socket用来监听:


Socket _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(_address, _port);
_listener.Bind(localEP);
_listener.Listen(100);

然后创建一个线程来处理客户端连接请求:


Thread _acceptWorkThread = new Thread(AcceptWorkThread);
_acceptWorkThread.Start();

private void AcceptWorkThread()
{
while (_isListener)
{
UserInfo info = new UserInfo();//这个UserInfo是用来保存客户信息的。
info.socket = socket;
Socket socket = _listener.Accept();
//这里进行其它处理。
socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, ReceiveCallBack, info);//这里向系统投递一个接收信息的请求,并为其指定ReceiveCallBack做为回调函数
}
} 我们再来看看回调函数的定义:
private void ReceiveCallBack(IAsyncResult ar)
{
UserInfo info = (UserInfo)ar.AsyncState;
Socket handler = info.socket;
int readCount = 0;
try
{
readCount = handler.EndReceive(ar);//调用这个函数来结束本次接收并返回接收到的数据长度。
}
catch (SocketException)//出现Socket异常就关闭连接
{
CloseSocket(info);//这个函数用来关闭客户端连接
return;
}
catch
{
}
if (readCount > 0)
{
byte[] buffer = new byte[readCount];
Buffer.BlockCopy(info.Buffer, 0, buffer, 0, readCount);
Analyzer(info, buffer);//这个函数用来处理接收到的信息。
try
{
handler.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);//向系统投递下一个接收请求
}
catch (SocketException) //出现Socket异常就关闭连接
{
CloseSocket(info);
}
catch
{
}
}
else //如果接收到0字节的数据说明客户端关闭了Socket,那我们也要关闭Socket
{
CloseSocket(info);
}
}
接下来我们看看如何发送数据给客户端:


public void Send(Socket socket, byte message)
{
try
{
info.socket.BeginSend(message, 0, _byte.Length, SocketFlags.None, new AsyncCallback(SendCallBack), info);//这里向系统投递一个发送数据的请求,并指定一个回调函数。
}
catch (SocketException ex)
{
CloseSocket(info);
}
catch
{
}
}
定义发送回调函数:


private void SendCallBack(IAsyncResult ar)
{
UserInfo info = (UserInfo)ar.AsyncState;
try
{
info.socket.EndSend(ar);//调用这个函数来结束本次发送。
}
catch
{
}
}

好了,整个监听、接收、发送的过程就完成了,很简单吧。现在需要说明的是,我在这里接收客户端连接的Accept是用的同步的,我个人认为在这里用同步的会比用异步好一些。因为这样代码简单而且没有性能上的损失。

今天我就写到这里了!下次我们再继续。

2 0 0
(请您对文章做出评价)

而线程池操作属于队列操作,如果单条处理步骤需要长时间的话,线程池就会被阻塞 无法执行下面的操作,所以在处理长时间处理或处理大量数据的线程时不宜用线池池,在使用短发而频率高的处理时宜使用线程池
绿色夹克衫 2010-01-19
  • 打赏
  • 举报
回复
如果是这样的话,又不能解释,为什么那么多书里都说线程池不适用于时间过长的任务。
除非这些书都是互相抄袭,最早出版的某本书是这么说的,所以大家都效仿。

(估计是我自己钻牛角尖了,可能除了一些必须在STA模式下跑的任务,剩下的都可以用线程池来做)

[Quote=引用 11 楼 fengjian_428 的回复:]
我的意思就是任务执行时间长短没关系 间隔长短有关系
[/Quote]
hitlcyu19 2010-01-19
  • 打赏
  • 举报
回复
帮顶哈
messi_yang 2010-01-19
  • 打赏
  • 举报
回复
只能幫你頂哈了···
fengjian_428 2010-01-19
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 litaoye 的回复:]
这个40秒应该是线程无事可做时,会自动销毁线程吧,这个问题似乎并不影响
ThreadPool执行那些时间较长的任务。

引用 6 楼 fengjian_428 的回复:
线程池内的线程通常挂起40秒钟 超过这个时间没有被启用便销毁
我觉得与其说执行时间长的任务不适合用线程池 不如说执行间隔长的任务不适合用线程池

[/Quote]
我的意思就是任务执行时间长短没关系 间隔长短有关系
绿色夹克衫 2010-01-19
  • 打赏
  • 举报
回复
这个例子是一个标准的需要使用线程池的任务,呵呵!
但如果是一个每次需要执行3-10秒,平均每分钟并发3-5个,最高并发10-20个的任务是否适用线程池呢?

[Quote=引用 7 楼 lianshaohua 的回复:]
你可以1毫秒创建一个线程,做50000个任务,每个任务用5毫秒或更短时间,然后再用线程池完成50000个任务,线程池设置为20-100个,

线程池里的线程一次创建,多次使用,真的省去了创建线程的时间,当然如果pool.size设置太大或太小,都会影响效率。。。。。。这需要根据具体的需求来设置。。。
[/Quote]
khjian 2010-01-19
  • 打赏
  • 举报
回复
UP
绿色夹克衫 2010-01-19
  • 打赏
  • 举报
回复
这个40秒应该是线程无事可做时,会自动销毁线程吧,这个问题似乎并不影响
ThreadPool执行那些时间较长的任务。

[Quote=引用 6 楼 fengjian_428 的回复:]
线程池内的线程通常挂起40秒钟 超过这个时间没有被启用便销毁
我觉得与其说执行时间长的任务不适合用线程池 不如说执行间隔长的任务不适合用线程池
[/Quote]
ztenv 2010-01-19
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 litaoye 的回复:]
如果是这个原因的话,用Thread来做同样也无法解决呀。
用ThreadPool的效果也不会比自己创建Thread差。

引用 2 楼 lianshaohua 的回复:
1、时间太久了,如果任务量一大,就把ThreadPool耗尽了。。。。。。另外一个达不到高效。。。ThreadPool的目的是减少频繁创建线程的消耗,。。。


[/Quote]

你可以1毫秒创建一个线程,做50000个任务,每个任务用5毫秒或更短时间,然后再用线程池完成50000个任务,线程池设置为20-100个,

线程池里的线程一次创建,多次使用,真的省去了创建线程的时间,当然如果pool.size设置太大或太小,都会影响效率。。。。。。这需要根据具体的需求来设置。。。
fengjian_428 2010-01-19
  • 打赏
  • 举报
回复
线程池内的线程通常挂起40秒钟 超过这个时间没有被启用便销毁
我觉得与其说执行时间长的任务不适合用线程池 不如说执行间隔长的任务不适合用线程池
绿色夹克衫 2010-01-19
  • 打赏
  • 举报
回复
如果是这个原因的话,用Thread来做同样也无法解决呀。
用ThreadPool的效果也不会比自己创建Thread差。

[Quote=引用 2 楼 lianshaohua 的回复:]
1、时间太久了,如果任务量一大,就把ThreadPool耗尽了。。。。。。另外一个达不到高效。。。ThreadPool的目的是减少频繁创建线程的消耗,。。。

[/Quote]
mxc1225 2010-01-19
  • 打赏
  • 举报
回复
学习!
绿色夹克衫 2010-01-19
  • 打赏
  • 举报
回复
因为这些资料里都没有讲清楚2个问题

晕,是3个问题,数都不会数了!
ztenv 2010-01-19
  • 打赏
  • 举报
回复
1、时间太久了,如果任务量一大,就把ThreadPool耗尽了。。。。。。另外一个达不到高效。。。ThreadPool的目的是减少频繁创建线程的消耗,。。。
wangping06 2010-01-19
  • 打赏
  • 举报
回复
up
zishanyan 2010-01-19
  • 打赏
  • 举报
回复
mark 学习

个人理解,使用threadpool应该是应对高并发,更有利于线程资源的利用。

但是当执行的任务时间较长的时候,会把其中的线程资源全部用光?所以不推荐使用?
可是如果同时面对高并发,长执行时间的情况又该怎么取舍?

这让我想到了网游里的排队机制,是优先服务器的稳定运行还是优先玩家的进入?

以上都是个人的理解,如果有不正确的地方还请指正。

ztenv 2010-01-19
  • 打赏
  • 举报
回复
如你所述,感觉可以不用线程池,意义不大,只是我的个人感觉!静听高手分析
绿色夹克衫 2010-01-19
  • 打赏
  • 举报
回复
法国的MVP写的那本书上说,几秒钟计算执行时间很长的了。
不过我个人感觉应该区别对待,如果是CPU占满几秒钟,那么确实运算量比较惊人(其实这种情况,不用说考虑线程池了,用线程意义都不大),如果是网络连接几秒钟,我觉得很正常了,本身异步的webservice也是基于线程池的,所以我觉得虽然需要几秒钟,也应该属于适用范围。

btw:除了主线程之外,应该没有其他线程需要并行了,因此估计不存在其它的任务并行的机会就很少了的情况。

[Quote=引用 24 楼 sp1234 的回复:]
既然每秒20个事务,那么肯定不是那种执行起来  -->  既然每分钟20个事务,那么几乎可以肯定不是那种执行起来
[/Quote]
lijun_xiao2009 2010-01-19
  • 打赏
  • 举报
回复
帮顶
加载更多回复(11)

111,092

社区成员

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

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

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