`
jackyhongvip
  • 浏览: 159601 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

多线程服务器的适用场合

阅读更多

本博文转自

陈硕 (giantchen_AT_gmail)  : http://blog.csdn.net/solstice/article/details/5334243

 

把评论也copy了,有点乱。

 

这篇文章原本是前一篇博客《多线程服务器的常用编程模型》(以下简称《常用模型》)计划中的一节,今天终于写完了。

“服务器开发”包罗万象,本文所指的“服务器开发”的含义请见《常用模型》一文,一句话形容是:跑在多核机器上的 Linux 用户态的没有用户界面的长期运行的网络应用程序。“长期运行”的意思不是指程序 7x24 不重启,而是程序不会因为无事可做而退出,它会等着下一个请求的到来。例如 wget 不是长期运行的,httpd 是长期运行的。

正名

与前文相同,本文的“进程”指的是 fork() 系统调用的产物。“线程”指的是 pthread_create() 的产物,而且我指的 pthreads 是 NPTL 的,每个线程由 clone() 产生,对应一个内核的 task_struct。本文所用的开发语言是 C++,运行环境为 Linux。

首先,一个由多台机器组成的分布式系统必然是多进程的(字面意义上),因为进程不能跨 OS 边界。在这个前提下,我们把目光集中到一台机器,一台拥有至少 4 个核的普通服务器。如果要在一台多核机器上提供一种服务或执行一个任务,可用的模式有:

  1. 运行一个单线程的进程
  2. 运行一个多线程的进程
  3. 运行多个单线程的进程
  4. 运行多个多线程的进程

这些模式之间的比较已经是老生常谈,简单地总结:

  • 模式 1 是不可伸缩的 (scalable),不能发挥多核机器的计算能力;
  • 模式 3 是目前公认的主流模式。它有两种子模式:
    • 3a 简单地把模式 1 中的进程运行多份,如果能用多个 tcp port 对外提供服务的话;
    • 3b 主进程+woker进程,如果必须绑定到一个 tcp port,比如 httpd+fastcgi。
  • 模式 2 是很多人鄙视的,认为多线程程序难写,而且不比模式 3 有什么优势;
  • 模式 4 更是千夫所指,它不但没有结合 2 和 3 的优点,反而汇聚了二者的缺点。

本文主要想讨论的是模式 2 和模式 3b 的优劣,即:什么时候一个服务器程序应该是多线程的。

从功能上讲,没有什么是多线程能做到而单线程做不到的,反之亦然,都是状态机嘛(我很高兴看到反例)。从性能上讲,无论是 IO bound 还是 CPU bound 的服务,多线程都没有什么优势。那么究竟为什么要用多线程?

在回答这个问题之前,我先谈谈必须用必须用单线程的场合。

必须用单线程的场合

据我所知,有两种场合必须使用单线程:

  1. 程序可能会 fork()
  2. 限制程序的 CPU 占用率

先说 fork(),我在《Linux 新增系统调用的启示》中提到:

fork() 一般不能在多线程程序中调用,因为 Linux 的 fork() 只克隆当前线程的 thread of control,不克隆其他线程。也就是说不能一下子 fork() 出一个和父进程一样的多线程子进程,Linux 也没有 forkall() 这样的系统调用。forkall() 其实也是很难办的(从语意上),因为其他线程可能等在 condition variable 上,可能阻塞在系统调用上,可能等着 mutex 以跨入临界区,还可能在密集的计算中,这些都不好全盘搬到子进程里。

更为糟糕的是,如果在 fork() 的一瞬间某个别的线程 a 已经获取了 mutex,由于 fork() 出的新进程里没有这个“线程a”,那么这个 mutex 永远也不会释放,新的进程就不能再获取那个 mutex,否则会死锁。(这一点仅为推测,还没有做实验,不排除 fork() 会释放所有 mutex 的可能。)

综上,一个设计为可能调用 fork() 的程序必须是单线程的,比如我在《启示》一文中提到的“看门狗进程”。多线程程序不是不能调用 fork(),而是这么做会遇到很多麻烦,我想不出做的理由。

一个程序 fork() 之后一般有两种行为:

  1. 立刻执行 exec(),变身为另一个程序。例如 shell 和 inetd;又比如 lighttpd fork() 出子进程,然后运行 fastcgi 程序。或者集群中运行在计算节点上的负责启动 job 的守护进程(即我所谓的“看门狗进程”)。
  2. 不调用 exec(),继续运行当前程序。要么通过共享的文件描述符与父进程通信,协同完成任务;要么接过父进程传来的文件描述符,独立完成工作,例如 80 年代的 web 服务器 NCSA httpd。

这些行为中,我认为只有“看门狗进程”必须坚持单线程,其他的均可替换为多线程程序(从功能上讲)。

单线程程序能限制程序的 CPU 占用率。

这个很容易理解,比如在一个 8-core 的主机上,一个单线程程序即便发生 busy-wait(无论是因为 bug 还是因为 overload),其 CPU 使用率也只有 12.5%,即占满 1 个 core。在这种最坏的情况下,系统还是有 87.5% 的计算资源可供其他服务进程使用。

因此对于一些辅助性的程序,如果它必须和主要功能进程运行在同一台机器的话(比如它要监控其他服务进程的状态),那么做成单线程的能避免过分抢夺系统的计算资源。

基于进程的分布式系统设计

《常用模型》一文提到,分布式系统的软件设计和功能划分一般应该以“进程”为单位。我提倡用多线程,并不是说把整个系统放到一个进程里实现,而是指功能划分之后,在实现每一类服务进程时,在必要时可以借助多线程来提高性能。对于整个分布式系统,要做到能 scale out,即享受增加机器带来的好处。

对于上层的应用而言,每个进程的代码量控制在 10 万行 C++ 以下,这不包括现成的 library 的代码量。这样每个进程都能被一个脑子完全理解,不会出现混乱。(其实我更想说 5 万行。)

这里推荐一篇 Google 的好文《Introduction to Distributed System Design》。其中点睛之笔是:分布式系统设计,是 design for failure。

本文继续讨论一个服务进程什么时候应该用多线程,先说说单线程的优势。

单线程程序的优势

从编程的角度,单线程程序的优势无需赘言:简单。程序的结构一般如《常用模型》所言,是一个基于 IO multiplexing 的 event loop。或者如云风所言,直接用阻塞 IO。

event loop 的典型代码框架是:

while (!done) {
  int retval = ::poll(fds, nfds, timeout_ms);
  if (retval < 0) {
    处理错误
  } else {
    处理到期的 timers
    if (retval > 0) {
      处理 IO 事件
    }
  }
}

event loop 有一个明显的缺点,它是非抢占的(non-preemptive)。假设事件 a 的优先级高于事件 b,处理事件 a 需要 1ms,处理事件 b 需要 10ms。如果事件 b 稍早于 a 发生,那么当事件 a 到来时,程序已经离开了 poll() 调用开始处理事件 b。事件 a 要等上 10ms 才有机会被处理,总的响应时间为 11ms。这等于发生了优先级反转。

这可缺点可以用多线程来克服,这也是多线程的主要优势。

多线程程序有性能优势吗?

前面我说,无论是 IO bound 还是 CPU bound 的服务,多线程都没有什么绝对意义上的性能优势。这里详细阐述一下这句话的意思。

这句话是说,如果用很少的 CPU 负载就能让的 IO 跑满,或者用很少的 IO 流量就能让 CPU 跑满,那么多线程没啥用处。举例来说:

  1. 对于静态 web 服务器,或者 ftp 服务器,CPU 的负载较轻,主要瓶颈在磁盘 IO 和网络 IO。这时候往往一个单线程的程序(模式 1)就能撑满 IO。用多线程并不能提高吞吐量,因为 IO 硬件容量已经饱和了。同理,这时增加 CPU 数目也不能提高吞吐量。
  2. CPU 跑满的情况比较少见,这里我只好虚构一个例子。假设有一个服务,它的输入是 n 个整数,问能否从中选出 m 个整数,使其和为 0 (这里 n < 100, m > 0)。这是著名的 subset sum 问题,是 NP-Complete 的。对于这样一个“服务”,哪怕很小的 n 值也会让 CPU 算死,比如 n = 30,一次的输入不过 120 字节(32-bit 整数),CPU 的运算时间可能长达几分钟。对于这种应用,模式 3a 是最适合的,能发挥多核的优势,程序也简单。

也就是说,无论任何一方早早地先到达瓶颈,多线程程序都没啥优势。

说到这里,可能已经有读者不耐烦了:你讲了这么多,都在说单线程的好处,那么多线程究竟有什么用?

适用多线程程序的场景

我认为多线程的适用场景是:提高响应速度,让 IO 和“计算”相互重叠,降低 latency

虽然多线程不能提高绝对性能,但能提高平均响应性能。

一个程序要做成多线程的,大致要满足:

  • 有多个 CPU 可用。单核机器上多线程的优势不明显。
  • 线程间有共享数据。如果没有共享数据,用模型 3b 就行。虽然我们应该把线程间的共享数据降到最低,但不代表没有;
  • 共享的数据是可以修改的,而不是静态的常量表。如果数据不能修改,那么可以在进程间用 shared memory,模式 3 就能胜任;
  • 提供非均质的服务。即,事件的响应有优先级差异,我们可以用专门的线程来处理优先级高的事件。防止优先级反转;
  • latency 和 throughput 同样重要,不是逻辑简单的 IO bound 或 CPU bound 程序;
  • 利用异步操作。比如 logging。无论往磁盘写 log file,还是往 log server 发送消息都不应该阻塞 critical path;
  • 能 scale up。一个好的多线程程序应该能享受增加 CPU 数目带来的好处,目前主流是 8 核,很快就会用到 16 核的机器了。
  • 具有可预测的性能。随着负载增加,性能缓慢下降,超过某个临界点之后急速下降。线程数目一般不随负载变化。
  • 多线程能有效地划分责任与功能,让每个线程的逻辑比较简单,任务单一,便于编码。而不是把所有逻辑都塞到一个 event loop 里,就像 Win32 SDK 程序那样。

这些条件比较抽象,这里举一个具体的(虽然是虚构的)例子。

假设要管理一个 Linux 服务器机群,这个机群里有 8 个计算节点,1 个控制节点。机器的配置都是一样的,双路四核 CPU,千兆网互联。现在需要编写一个简单的机群管理软件(参考 LLNL 的 SLURM),这个软件由三个程序组成:

  • 运行在控制节点上的 master,这个程序监视并控制整个机群的状态。
  • 运在每个计算节点上的 slave,负责启动和终止 job,并监控本机的资源。
  • 给最终用户的 client 命令行工具,用于提交 job。

根据前面的分析,slave 是个“看门狗进程”,它会启动别的 job 进程,因此必须是个单线程程序。另外它不应该占用太多的 CPU 资源,这也适合单线程模型。

master 应该是个模式 2 的多线程程序:

  • 它独占一台 8 核的机器,如果用模型 1,等于浪费了 87.5% 的 CPU 资源。
  • 整个机群的状态应该能完全放在内存中,这些状态是共享且可变的。如果用模式 3,那么进程之间的状态同步会成大问题。而如果大量使用共享内存,等于是掩耳盗铃,披着多进程外衣的多线程程序。
  • master 的主要性能指标不是 throughput,而是 latency,即尽快地响应各种事件。它几乎不会出现把 IO 或 CPU 跑满的情况。
  • master 监控的事件有优先级区别,一个程序正常运行结束和异常崩溃的处理优先级不同,计算节点的磁盘满了和机箱温度过高这两种报警条件的优先级也不同。如果用单线程,可能会出现优先级反转。
  • 假设 master 和每个 slave 之间用一个 TCP 连接,那么 master 采用 2 个或 4 个 IO 线程来处理 8 个 TCP connections 能有效地降低延迟。
  • master 要异步的往本地硬盘写 log,这要求 logging library 有自己的 IO 线程。
  • master 有可能要读写数据库,那么数据库连接这个第三方 library 可能有自己的线程,并回调 master 的代码。
  • master 要服务于多个 clients,用多线程也能降低客户响应时间。也就是说它可以再用 2 个 IO 线程专门处理和 clients 的通信。
  • master 还可以提供一个 monitor 接口,用来广播 (pushing) 机群的状态,这样用户不用主动轮询 (polling)。这个功能如果用单独的线程来做,会比较容易实现,不会搞乱其他主要功能。
  • master 一共开了 10 个线程:
    • 4 个用于和 slaves 通信的 IO 线程
    • 1 个 logging 线程
    • 1 个数据库 IO 线程
    • 2 个和 clients 通信的 IO 线程
    • 1 个主线程,用于做些背景工作,比如 job 调度
    • 1 个 pushing 线程,用于主动广播机群的状态
  • 虽然线程数目略多于 core 数目,但是这些线程很多时候都是空闲的,可以依赖 OS 的进程调度来保证可控的延迟。

综上所述,master 用多线程方式编写是自然且高效的。

线程的分类

据我的经验,一个多线程服务程序中的线程大致可分为 3 类:

  1. IO 线程,这类线程的的主循环是 io multiplexing,等在 select/poll/epoll 系统调用上。这类线程也处理定时事件。当然它的功能不止 IO,有些计算也可以放入其中。
  2. 计算线程,这类线程的主循环是 blocking queue,等在 condition variable 上。这类线程一般位于 thread pool 中。
  3. 第三方库所用的线程,比如 logging,又比如 database connection。

服务器程序一般不会频繁地启动和终止线程。甚至,在我写过的程序里,create thread 只在程序启动的时候调用,在服务运行期间是不调用的。

 

在多核时代,多线程编程是不可避免的,“鸵鸟算法”不是办法。

20楼 qqmsyz520 2011-05-03 16:46发表 [回复]
博主你好 文中是不是不考虑业务的处理啊或者说文中所说的服务器不包括业务的处理:FTP服务器是 “单线程单进程”的话,用户A请求文件传输的,服务器正在文件和网络(与用户A)IO中,这时用户B要与服务器交互(请求,登录,建立连接等),单线程单进程服务器是如何做到的?在IO的同时处理B的请求么?
Re: Solstice 2011-05-03 17:49发表 [回复]
回复 qqmsyz520: IO-multiplexing + non-blocking IO
Re: qqmsyz520 2011-05-04 21:26发表 [回复]
回复 Solstice:了解了 thx
19楼 shendl 2011-03-29 18:20发表 [回复]
楼主又胡说了! 多进程只会比多线程快,不会比多线程慢! 你一个进程8个线程算,需要同步内存吧? 我八个进程一起算,不需要同步。 怎么会比你慢! 多进程的缺点就是多用一点内存而已。
Re: liigo 2011-04-15 13:16发表 [回复]
回复 shendl:呵呵,相同的任务,如果用多进程不需要同步,用多线程也不需要同步啊。所以你这样论据可能不成立。
18楼 lckj2009 2011-02-22 11:41发表 [回复]
我想问一下,关于博主的“有多个 CPU 可用。单核机器上多线程的优势不明显。”

那么INTER的CPU单核支持多线程的目的是什么,这样做能给他带来的好处是什么。
Re: Solstice 2011-02-22 12:34发表 [回复]
回复 lckj2009: “支持多线程”不是 CPU 的事,是操作系统的事。如果 CPU 能运行现代的多任务操作系统,那么它肯定能支持多线程。Intel 其实没办法让它的单核 IA32 CPU 不支持多线程。
Re: lckj2009 2011-04-15 10:41发表 [回复]
回复 Solstice:

(接)
虽然我对这个不是很了解,但是我想,单核时代对多线程的支持也只能以模拟的方式进行,虽然INTER的P4就已经支持单核多线程。但我知道那也是模拟的。我只是想知道P4和模拟和P4以前早起的CPU的模拟有和不同。
Re: Solstice 2011-04-15 10:58发表 [回复]
回复 lckj2009:你说的那个术语叫&quot;超线程&quot;,可以搜到很多文章。
Re: lckj2009 2011-04-15 10:40发表 [回复]
回复 Solstice:
我是从硬件的角度上去说的,就是说从CPU的角度去考虑他对多线程的支持的。其实,无论是单核时代还是多核时代,都是支持多线程。而我的意思是支持的效果。
17楼 匿名用户 2010-03-19 16:29发表 [回复]
你好,博主,你的很多观点我很赞同。

不知道你有没有考虑过多个IO线程,处理IO;
多个逻辑线程处理业务。

这时候不可避免的是带来了很多CPU的上下文切换,我现在的程序就碰到了这种问题。

不知道博主有没有比较好的解决方案。
Re: Solstice 2010-03-19 19:44发表 [回复]
回复 匿名用户:你的问题描述不清楚。你用的是什么机器?几个核?多少个 IO 线程?什么类型的 IO?开多少个业务线程?业务的计算量有多大?你期望的性能指标是多少?现在能达到多少?
Re: 匿名用户 2010-03-22 14:29发表 [回复]
回复 Solstice:出现这种情况之后,我就不断分析原因,最终就定位到,由IO线程确定完一个完整的逻辑包后,交给Logic线程去处理,这里带来的CPU切换很多,所以我想问问博主有没有比较好的解决方案。
Re: Solstice 2010-03-22 23:34发表 [回复]
回复 匿名用户:有,但是这里空白太小,写不下。
Re: 匿名用户 2010-03-23 10:58发表 [回复]
回复 Solstice:我的gmail是spriteray,博主把解决方案发邮件给我吧,谢谢~
Re: Solstice 2010-03-23 11:29发表 [回复]
回复 匿名用户:在 twitter 上谈吧。
Re: liigo 2011-04-15 13:13发表 [回复]
回复 Solstice:CSDN单条评论限制150字,twitter上限制140字
Re: 匿名用户 2010-03-22 14:22发表 [回复]
回复 Solstice:我的意思是,在多个IO线程和多个逻辑线程的这种框架下,CPU上下文切换会很多。
1、什么类型的 IO?--IO线程做的工作就只有,接收数据,并判断是否是一个完整的逻辑包,并把数据包放入队列中,让逻辑线程去处理。
2、我在4核的机器上做过1个(行)回显服务器的测试,4000个客户端不断发20个600字节的数据包,服务器每秒种处理10W多个请求,吞吐量已经达到我的设计要求,但CPU的上下文切换达到了27W多,system消耗掉40%的CPU时间。
15楼 run_mfk 2010-03-10 19:16发表 [回复]
回复 Solstice:呵呵,你是将问题单一化了,你假定了不同任务使用不同资源的比例是相同的

比如一台pc机,有一台串口设备每秒能读100个字节,cpu 每秒能计算1000次,现在有两个Job: 1.从串口设备中读数据每次10个字节,并占用cpu的10次计算,2.仅占用cpu的10次计算,两种job中job1优先级高时,现在请求如下,每秒两者的请求数超过10个.

如果是单线程话,吞吐量是10个/秒,而多线程则是100个/秒

综上,所说无论是多进程还是多线程有两个目的
1.让任何并发运行,提高设备的资源利用率,以提高任务的吞吐量
2.简化程序的开发复杂度,因为与其于IO multiplexing 的 event loop 模式来说,后者的难度要高很多.

至于多进程还是多线程对这种任务级的开发来说区别不大,只不过谁更方便.

对于用多线程而不用多进程,我认为不是你所说的&quot;多线程的适用场景是:提高响应速度,让 IO 和“计算”相互重叠,降低 latency。&quot;,我认为是原因如下
1. 多进程耗费的系统资源较多
2. 提高响应速度,因为起动一个线程比起动一个进程快的多
3. 多个任务之间的通信与协调更方便,更灵活,手段更多.
14楼 run_mfk 2010-03-10 19:10发表 [回复]
回复 Solstice:呵呵,你是将问题单一化了,你假定了不同任务使用不同资源的比例是相同的

比如一台pc机,有一台串口设备每秒能读100个字节,cpu 每秒能计算1000次,现在有两个Job: 1.从串口设备中读数据每次10个字节,并占用cpu的10次计算,2.仅占用cpu的10次计算,两种job中job1优先级高时,现在请求如下,每秒两者的请求数超过10个.

如果是单线程话,吞吐量是10个/秒,而多线程则是100个/秒

综上,所说无论是多进程还是多线程有两个目的
1.让任何并发运行,提高设备的资源利用率,以提高任务的吞吐量
2.简化程序的开发复杂度,因为与其于IO multiplexing 的 event loop 模式来说,后者的难度要高很多.

至于多进程还是多线程对任务级的开发来说区别不大,只不过谁更方便.
12楼 mphyatcd 2010-03-02 21:28发表 [回复]
“多线程的适用场景是:提高响应速度,让 IO 和“计算”相互重叠,降低 latency。”,我估计这句话是中心思想,也就是什么情况下应用“多线程”, 不用“多进程”的原因。

但是,我从文章中没有找到支持这个结论的论据,从论述中看不出为什多县城能够让IO和计算重叠,降低延迟:)

下面是我的理解,开发这决定使用多进程模型的原因是:

1、在某些情况,相对于单进程来说,多进程模型编程简单。例如:典型的网络服务器程序,如telnetd、httpd,如果用单进程模型来编写,会比较麻烦。一个进程里面既要接受(accept)新的网络连接,也要接收每个现有连接上的数据,还要为每个连接上接收的报文发送相应。这是一件很麻烦的事情,要用select进行多路选择,然后找到相应的数据,在做相应的动作。而用多进程模型编程,就比较简单。

2、为了性能更好,一方面,能够充分利用多核,多CPU。另外一方面,即便在单核、单CPU系统上,多个进程所获得的CPU时间也比单个进程多。并不是说要用多进程去强抢CPU资源,而是在CPU资源紧张的情况下,利用多进程变成是合理分配整个系统CPU时间的一种手段。

我理解,开发者决定使用多线程,而非多进程,主要原因还是:(a)认为多线程编程更简单;(b)提高性能。

如果在某些应用中,有大量共享数据,那么这种情况下,多线程比多进程更简单。在某些情况下,多线程可能比多进程的性能好一点,例如,很多操作系统下面进程之间切换的时候,需要刷新TLB,线程之间切换的时候则不需要。
Re: Solstice 2010-03-02 21:38发表 [回复]
回复 mphyatcd:过几天会发一篇“多线程编程的实例分析与反模式”,希望能回答你的疑问。
11楼 Solstice 2010-03-02 19:56发表 [回复]
致楼上各位“匿名用户”:
我一般不回复匿名用户的提问,因为匿名用户的 identity 不明,我搞不清楚自己是在跟谁讲话。(比如我搞不清楚楼上匿名背后的是一个人还是几个人,哪些话是同一个人说的,等等)。如果希望我解答疑惑,请:
1. 给我写信(我的信箱已经在文中列出),2. 在 twitter 上 follow @bnu_chenshuo,3. 登陆以后评论(我不要求您实名,但不能无名,对吧。)。如有不便,还请见谅。
至于为什么 slave 要是单线程,我文中已经说清楚了,slave 可能 fork() 出新进程,所以必须是单线程的。
Re: liigo 2011-04-15 13:07发表 [回复]
回复 Solstice:人不可貌相,亦不可“名”相。具名也好匿名也罢,对于讨论具体问题不发生影响。
10楼 tony7758 2010-03-02 17:03发表 [回复]
如果 服务器负载比较高 并行计算中的负载均衡就显得过于复杂 否则算法虽是并行的 但依然得到是串行算法时间 甚至更慢...
9楼 匿名用户 2010-03-02 15:44发表 [回复]
麻烦您解释一下为什么关系数据库的基本模型多为多线程模型?
6楼 匿名用户 2010-03-02 14:16发表 [回复]
还有你那个master,slave的例子,谁说了slave就一定是单线程呢?如果还是“大任务阻塞了优先级高的小任务呢?”
5楼 匿名用户 2010-03-02 14:14发表 [回复]
整篇文章就“无论任何一方早早地先到达瓶颈,多线程程序都没啥优势。”这句话说明了作者的论点,但完全不认同这句话;

就拿1ms和10ms那个例子,这里为了解决:“大任务阻塞小任务的问题”而必须使用多线程;并非因为“IO或者CPU到达了瓶颈”;

对于线程的分类,1)2)很不错,3为第三方库所用的线程,这个完全无法理解;
3楼 匿名用户 2010-03-01 22:24发表 [回复] [引用] [举报]
“无论任何一方早早地先到达瓶颈,多线程程序都没啥优势。”
这句不认同,博主显然忽视了多线程的并行算法,对于CPU bound的计算,用并行算法可以得到更好的性能,特别是对于有大量共享状态的服务而言,parallel算法可以充分利用多核优势,当然这里所说的parallel算法跟传统意义上的concurrency多线程程序是不一样的概念。
Re: Solstice 2010-03-02 20:53发表 [回复] [引用] [举报]
回复 匿名用户:假设有一个耗时的计算服务,用单线程算需要 0.8s。在一台 8 核的机器上,启动 8 个进程一起对外服务,完成单个计算仍然要 0.8s,由于这些进程的计算可以同时进行,理想情况下吞吐量可以从单核的 1.25cps (calc per second) 上升到 10cps。假设改用并行算法,用 8 个核一起算,理论上如果完全并行,加速比高达 8,那么计算时间是 0.1s,吞吐量还是 10cps,但是单次请求的响应时间却降低了很多。实际上并行算法由于其他的开销,完成单次运算的时间可能比 0.1s 略长(另见Amdahl's law),这样会造成吞吐量略微下降,不过以此为代价,换得响应时间的提升,有时也是值得的。因此我说多线程不能提高吞吐量,但能加快响应速度。
Re: run_mfk 2010-03-10 19:08发表 [回复] [引用] [举报]
回复 Solstice:呵呵,你是将问题单一化了,你假定了不同任务使用不同资源的比例是相同的

比如一台pc机,有一台串口设备每秒能读100个字节,cpu 每秒能计算1000次,现在有两个Job: 1.从串口设备中读数据每次10个字节,并占用cpu的10次计算,2.仅占用cpu的10次计算,两种job中job1优先级高时,现在请求如下,每秒两者的请求数超过10个.

如果是单线程话,吞吐量是10个/秒,而多线程则是100个/秒

综上,所说无论是多进程还是多线程有两个目的
1.让任何并发运行,提高设备的资源利用率,以提高任务的吞吐量
2.简化程序的开发复杂度,因为与其于IO multiplexing 的 event loop 模式来说,后者的难度要高很多.

至于多进程还是多线程对任务级的开发来说区别不大,只不过谁更方便.
Re: run_mfk 2010-03-11 08:37发表 [回复] [引用] [举报]
回复 run_mfk:呵呵,你是将问题单一化了,你假定了不同任务使用不同资源的比例是相同的

比如一台pc机,有一台串口设备每秒能读100个字节,cpu 每秒能计算1000次,现在有两个Job: 1.从串口设备中读数据每次10个字节,并占用cpu的10次计算,2.仅占用cpu的10次计算,两种job中job1优先级高时,现在请求如下,每秒两者的请求数超过10个.

如果是单线程话,吞吐量是10个/秒,而多线程则是100个/秒

综上,所说无论是多进程还是多线程有两个目的
1.让任务并发运行,提高设备的资源利用率,以提高任务的吞吐量
2.简化程序的开发复杂度,因为与其于IO multiplexing 的 event loop 模式来说,后者的难度要高很多.

至于多进程还是多线程对这种任务级的开发来说区别不大,只不过谁更方便.

对于用多线程而不用多进程,我认为不是你所说的&quot;多线程的适用场景是:提高响应速度,让 IO 和“计算”相互重叠,降低 latency。&quot;,我认为是原因如下
1. 多进程耗费的系统资源较多
2. 提高响应速度,因为起动一个线程比起动一个进程快的多
3. 多个任务之间的通信与协调更方便,更灵活,手段更多.
分享到:
评论
1 楼 西巴拉古呀那 2018-02-21  
Linux多线程并发服务器编程(线程池,FTP服务器)
网盘地址:https://pan.baidu.com/s/1ghaVa07 密码: m4id
备用地址(腾讯微云):http://url.cn/5Ui0kn7 密码:0MIoiD

相关推荐

    多线程服务器的适用场合-陈硕1

    在IT行业中,多线程服务器的适用场合是一个重要的议题,特别是在设计高性能、高并发的网络应用时。本文主要探讨了四种不同的进程与线程模式,并分析了它们在多核服务器环境下的优劣。 1. 单线程进程:这种模式不...

    《多线程服务器的适用场合例释与答疑-陈硕1

    这篇讨论主要围绕《多线程服务器的适用场合》一文的例释与答疑展开,作者陈硕通过问答形式深入剖析了多线程服务器在不同场景下的表现。 首先,针对“Linux能同时启动多少个线程”的问题,32位Linux系统中,一个进程...

    多线程服务器的几种常用模型

    此外,进程间通信和线程间同步是实现多线程服务器的关键技术,通过合理的设计和使用可以有效地解决并发问题。 最后,作者提到的“Sleep反模式”是指在多线程程序中不应使用简单的`sleep()`来实现等待,因为这样会...

    基于mongoose实现Http Server(多线程)

    - `main.c` 或类似文件:这是项目的主程序,实现了多线程服务器的启动和配置。 - 可能还包括其他辅助文件,如配置文件、测试用例等。 **总结** 通过使用mongoose库并结合多线程技术,开发者可以快速构建一个高效的...

    多线程编程的各种适用环境说明

    本文主要探讨了四种常见的服务执行模式,并重点分析了多线程和多进程在服务器开发中的优缺点。 1. **单线程进程**:这种模式下,程序仅使用一个线程来处理所有任务。由于只有一个执行线程,无法充分利用多核处理器...

    QT下多线程 UDP socket示例

    QT下多线程UDP Socket示例是一个典型的网络通信编程应用场景,它涉及到QT库中的网络模块,特别是关于UDP(用户数据报协议)的使用以及多线程技术。在本示例中,开发者创建了一个UDP服务器,该服务器能够在不影响主...

    实验二、嵌入式Linux多线程编程实验

    在实验过程中,学生不仅需要掌握多线程编程的理论知识,还要具备实际编程和调试能力,通过实际操作加深对线程同步和互斥、信号量机制的理解,以及Makefile的编写和使用。这对于提升嵌入式系统的开发和维护技能至关...

    一个简单的OpenGL多线程渲染模型

    本文研究了基于OpenGL的动态多场景并行渲染,使用多线程技术实现了 OpenGL 动态多场景的并行渲染,并给出了虚拟烟花和碎片的实例。 一、OpenGL概述 OpenGL(Open Graphics Library)是一种性能卓越的三维图形标准...

    Socket通讯与多线程处理-完整实例

    1. `server.py`: 服务器端的代码,包含Socket的创建、绑定、监听和接受连接,以及使用多线程处理客户端请求的部分。 2. `client.py`: 客户端的代码,包含Socket的创建、连接以及发送和接收数据的功能。 3. `config....

    多线程UDP传送文件示例

    开发者可能使用这个库来创建多线程环境下的UDP客户端和服务器,每个线程负责一部分文件的数据传输。文件名列表中的"mmzmagic_PeerToPeer.gif"暗示了这是一个关于点对点(Peer-to-Peer, P2P)通信的例子,P2P网络中,每...

    Linux多线程服务端编程:使用muduo C++网络库

    《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。...

    多线程代理架构,多线程验证IP,方便多线程操作时调用

    5. **应用场合**:描述中提到的这套架构适合直接嵌入到程序员的项目中,用于多线程操作,特别是那些涉及大量网络请求的场景。例如,网络爬虫、大规模数据抓取或分布式任务执行等。 结合标签“易语言 多线程 代理...

    C++基于socket的多线程聊天程序

    本项目"基于socket的多线程聊天程序"是使用C++语言在Windows环境下,利用Microsoft Visual C++ 6.0(简称VC6.0)开发的一款群聊应用程序。下面我们将详细探讨其中涉及的关键知识点。 1. **Socket编程**:Socket是...

    Java多线程文章系列.pdf

    #### 八、用Java实现多线程服务器程序 ##### 1. Java中的服务器程序与多线程 - **模型**: - 单线程服务器模型。 - 多线程服务器模型。 - 线程池服务器模型。 ##### 2. 多线程服务器程序举例 - **实现步骤**: -...

    MultiHttp高性能的PHP封装的HTTPRestful多线程并发请求库

    4. **多线程并发请求**:在编程中,多线程允许同时执行多个任务,提高程序的执行效率。并发请求指的是在单个执行上下文中同时发送多个HTTP请求,提高了数据获取的速度。 5. **库**:在软件开发中,库是一组预先编写...

    用户级线程的介绍,怎样实现多线程等等

    例如,在Web服务器中,Servlet可以利用多线程处理并发的HTTP请求,提高服务器响应效率。实现多线程的方式有多种,例如在一个servlet中全局保存请求,然后由单例servlet处理,或者将请求放入队列,由单线程调度处理。...

    c语言多进程多线程编程.doc

    在计算机编程领域,C语言是一种强大的工具,尤其在实现多进程和多线程编程时。...在互联网环境中,多进程和多线程技术广泛应用于服务器开发、实时系统和分布式系统,是现代软件开发不可或缺的一部分。

    C++任务队列与多线程

    多线程是开发C++服务器程序非常重要的基础,如何根据需求具体的设计、分配线程以及线程间的通信,也是服务器程序非常重要的部分,除了能够带来程序的性能提高外,若设计失误,则可能导致程序复杂而又混乱,变成bug...

Global site tag (gtag.js) - Google Analytics