进程还是线程?这是个问题! by 编程随想

76 views
Skip to first unread message

pongba

unread,
Feb 22, 2009, 8:06:34 AM2/22/09
to TopLanguage
还记得列表里面以前争吵过的进程vs线程的问题吗?

来自: http://program-think.blogspot.com/2009/02/multi-process-vs-multi-thread.html

  就像莎士比亚的"To be, or not to be, that is the question"始终困扰着哈姆雷特,对于"进程还是线程?"这个问题,也经常困扰着那些进行软件架构设计的家伙。所以今天打算聊一下我对这个问题的体 会。假如你还搞不清楚线程和进程的区别,请先找本操作系统原理的书好好拜读一下,再回来看帖。
  由于这个问题很容易引发口水战,事先声明如下:多进程和多线程,无法一概而论地说谁比谁好。因此本帖主要描述特定场景(与我所负责的产品相关)下,进程和线程的权衡经验,仅供大伙儿参考。
  由于特定场景是本帖讨论的前提,先说说我目前负责的产品的特点:业务逻辑比较复杂、业务数据量比较大、对数据实时处理的性能要求比较高、对健壮性和安全性要求比较高、要求跨平台(包括操作系统、数据库)、某些情况下需要分布部署。
  上面说了一大堆,其实有不少的应用系统符合上述特点,比如:某些游戏服务器、某些金融方面的业务系统、某些电子商务系统等等。如果你正在从事的是类似的应用系统的设计,希望我下面介绍的经验对你有帮助。

  ★进程颗粒度问题
  大伙儿应该明白,进程和线程都是处理并发(concurrency)的手段。对于上述这种比较复杂的系统,如果你企图全部用进程(见注1)或者全部用线程(见注2)来处理并发,估计会死得很难看。所以,关键问题就是如何在进程和线程之间进行平衡(也就是确定进程颗粒度的问题)。
  我个人建议,尽量以业务逻辑的单元来划分进程。这样做的好处有如下几点:
  1、避免扯皮
  一般来说,某个固定业务逻辑的开发人员也是相对固定的。如果业务逻辑对应的某个进程崩溃了,测试人员容易快速定位肇事者,然后直接提交Bug给他/她。
  反之,一个进程搞得太庞大,N多人掺和在里面,一旦进程崩溃了,相关编程人员之间很容易互相扯皮,不利于维护安定团结的局面;另外,由于测试人员经常搞不清楚Bug属于谁,经常给错Bug,也容易制造人民内部矛盾。
  从上面可以看出来,相对细的进程颗粒度能够避免一些管理上的麻烦。由于XXX经常教导我们:"稳定压倒一切",所以该优点列第一条。
  2、健壮性、容错性
  一般来说,开发人员的水平参差不齐,优秀的毕竟是少数(具体参见"二八原理系列"的帖子)。所以难免会有菜鸟程序员搞出低级错误,而有些低级错误是致命的,会导致进程的崩溃。
  如果你是以业务逻辑划分进程,一个业务逻辑的进程崩溃,对其它业务逻辑的影响不大(除非是该业务逻辑的依赖方);因此就不会出现"注2"提到的问题。
  3、分布式
  我常碰见的分布式部署需求,一般都是按照业务逻辑的维度来划分。比如系统中有一个认证模块,里面包含有敏感的用户认证信息。这时候客户就会要求把该模块单独部署在一台经过安全加固的主机中(以防阶级敌人搞破坏)。
  如果是以业务逻辑为单位划分进程,要满足上述的部署需求就相对容易了(只要再配合恰当的进程间通讯机制,下面会提到)。
  另外,支持分布式部署还可以顺带解决性能问题。比如某个业务逻辑模块特别消耗硬件资源(比如内存、CPU、硬盘、带宽),就可以把它拿出去单独放一台机器上跑。
  4、跨编程语言
  这个好处可能很多人容易忽略。一般来说,每个编程语言都有各自的优缺点。如果你通过业务逻辑划分进程,就可以根据不同的业务逻辑的特点来选择合适的编程语言。
  比如:对于性能敏感的模块,我就使用C++搞定;而对于一些业务逻辑密集型的模块,则使用Java或Python开发。

  ★进程间通讯(以下简称IPC)问题
  既然不可能把整个系统放入一个进程,那就必然会碰到IPC的问题。下面就来说一下该如何选择IPC。
  各种操作系统里面,有很多稀奇古怪的IPC类型。由于要考虑跨平台,首先砍掉一批(关于IPC的跨平台问题,我在"跨平台开发"系列中会提到)。剩下的IPC类型中,能够进行数据传输的IPC就不多了,主要有如下几种:套接字(以下简称Socket)、共享内存、管道、文件。
   其中Socket是我强烈推荐的IPC方式,理由如下:使用Socket可以天然地支持分布式部署;使用Socket可以比较容易地实现多种编程语言的 混合(比如C++、Java、Python、Flex都支持Socket);使用Socket还可以省掉了一大坨"锁操作"的代码。
  列位看官 中,或许有人在担心Socket的性能问题,其实大可不必多虑。当两个进程在本机上进行Socket通讯时,由于可以使用localhost环回地址,数 据不用经过物理网卡,操作系统内核还可以进行某些优化。这种情况下,Socket相对其它几种IPC机制,不会有太大的性能偏差。
  最后再补充 一下,Socket方式也可以有效防止扯皮问题。举个例子:张三写了一个进程A,李四写了一个进程B,进程A通过Socket方式发数据给进程B。突然有 一天,两个进程的通讯出故障了。然后张三就说是李四接收数据出错;李四就说张三发送数据出错。这时候怎么办捏?很简单,随便找个Sniffer软件当场抓 一下数据包并Dump出来看,问题就水落石出了。

  ★为啥还要线程?
  上面说了这么多进程的好处,有同学要问了:"那线程有什么用捏?"总的来说,使用线程出于两方面的考虑:性能因素和编码方便。
  1、性能因素
  由于某些操作系统(比如Windows)中的进程比较重型,如果频繁创建进程或者创建大量进程,会导致操作系统的负载过高。举例如下:
  假设你要开发一个类似Web Server的应用。你针对每一个客户端请求创建一个对应的进程用于进行数据交互(是不是想起了古老的CGI :-)。一旦这个系统扩容,用户的并发连接数一增加,你的应用立马死翘翘。
  上面的例子表明,跨平台软件系统的进程数要保持相对稳定。如果你的进程数会随着某些环境因素呈线性增长,那就相当不妙了。而根据业务逻辑的单元划分进程,顺便能达到"进程数的相对稳定"的效果。
  2、编码方面
  由于业务逻辑内部的数据耦合比较紧密。如果业务逻辑内部的并发也用进程来实现,就会导致大量的IPC编码(任意两个进程之间只要有数据交互,就得写一坨IPC代码)。这会让相关的编程人员怨声载道。

  写到这里,看看篇幅有点超,就此打住。大伙儿如有不同看法,请到评论中拍砖。
---------------------------------------------------
  注1
  所谓"全部用进程",就是所有的并发都使用进程实现(因此每个进程只有一个线程)。这种设计在某些平台上(比如Windows)会导致严重的性能问题。

  注2
  所谓"全部用线程",就是所有的并发都使用线程实现(因此整个系统只有一个进程)。这种设计的健壮性极差(一个致命错会导致整个系统崩溃),而且更别提分布部署了。

--
刘未鹏(pongba)
Blog | Mind Hacks
http://mindhacks.cn
TopLanguage
http://groups.google.com/group/pongba

sjinny

unread,
Feb 22, 2009, 9:30:38 AM2/22/09
to pon...@googlegroups.com
恩,对这个话题很感兴趣。
其实一开始看到“健壮”、“安全”、“分布部署”这些词的时候我就知道了,作者会使用进程来实现这些,而线程仅仅只是一种性能优化的手段。从我的角度来看,这时线程机制的作用就只是锦上添花而已,而进程机制则成为整个系统的支柱。
对里面提到的两个问题的看法:
1.使用线程进行性能优化的问题
按照文中的描述,使用线程来做性能优化而不是使用进程来做性能优化,是因为一个新的用户session会使用一个新的进程来处理,这样用户多的时候性能就会成为一个问题,而线程比进程更加轻便,所以使用了线程来做优化。但是线程的轻便只是相对于进程而言的,如果真的是一个用户连接对应一个线程,那么这个系统的承载能力仍然非常有限。
想起我以前开始做网络模块的时候,一开始看到的提供并发能力的方案就两种:多进程和多线程。当后来搞明白了select、poll和epoll的时候,越来越觉得使进程数或线程数与用户访问数直接相关是很糟糕的做法,因为你很难假设以后用户访问会不会增加以及增加到什么程度,而进程或线程则一直都是操作系统中昂贵的资源。所以文中举的那个用线程做性能优化的例子并不合适,那个问题我觉得还是用异步的方式会更好些。
性能优化时,使用线程比进程更合适的情况我现在只能想到这一种:线程之间需要交换大量的数据,并且无法或难以使用共享内存来实现交换。
2.使用线程来避免IPC时的繁琐操作的问题
我觉得IPC并不必然是繁琐的,其实我觉得对于参与通信的进程来说IPC应该是透明的,这样逻辑功能直接的交互不仅不会导致“大量的IPC编码”,甚至不会导致任何IPC编码。
就简单的IPC来说,其实已经做到了透明,比如管道,对于管线上的一环来说,它只是读写stdio而已,并不需要做任何特殊的处理,可能一个进程开发的时候完全就是一个独立的程序而不是作为一个分布式系统的一部分,之后使用了netcat和管道就加入了一个分布式系统,而这个进程不需要为此做任何修改。
我这段时间的尝试就是做出一个程序,它能够为其他进程提供透明的IPC服务,不仅能支持1对1的通信,而且能支持m对n的通信。以前做过的网络模块,不管怎么样设计,使用的时候仍然需要使用特定的头文件、库文件和函数调用,甚至会影响到使用它的程序的设计,这次这个东西的目标就是它的使用不会影响使用者自己的设计。

在2009-02-22,pongba <pon...@gmail.com> 写道:
还记得列表里面以前争吵过的进程vs线程的问题吗?

来自: http://program-think.blogspot.com/2009/02/multi-process-vs-multi-thread.html

  就像莎士比亚的"To be, or not to be, that is the question"始终困扰着哈姆雷特,对于"进程还是线程?"这个问题,也经常困扰着那些进行软件架构设计的家伙。所以今天打算聊一下我对这个问题的体会。假如你还搞不清楚线程和进程的区别,请先找本操作系统原理的书好好拜读一下,再回来看帖。

  由于这个问题很容易引发口水战,事先声明如下:多进程和多线程,无法一概而论地说谁比谁好。因此本帖主要描述特定场景(与我所负责的产品相关)下,进程和线程的权衡经验,仅供大伙儿参考。
  由于特定场景是本帖讨论的前提,先说说我目前负责的产品的特点:业务逻辑比较复杂、业务数据量比较大、对数据实时处理的性能要求比较高、对健壮性和安全性要求比较高、要求跨平台(包括操作系统、数据库)、某些情况下需要分布部署。
  上面说了一大堆,其实有不少的应用系统符合上述特点,比如:某些游戏服务器、某些金融方面的业务系统、某些电子商务系统等等。如果你正在从事的是类似的应用系统的设计,希望我下面介绍的经验对你有帮助。

  ★进程颗粒度问题
  大伙儿应该明白,进程和线程都是处理并发(concurrency)的手段。对于上述这种比较复杂的系统,如果你企图全部用进程(见注1)或者全部用线程(见注2)来处理并发,估计会死得很难看。所以,关键问题就是如何在进程和线程之间进行平衡(也就是确定进程颗粒度的问题)。
  我个人建议,尽量以业务逻辑的单元来划分进程。这样做的好处有如下几点:
  1、避免扯皮
  一般来说,某个固定业务逻辑的开发人员也是相对固定的。如果业务逻辑对应的某个进程崩溃了,测试人员容易快速定位肇事者,然后直接提交Bug给他/她。
  反之,一个进程搞得太庞大,N多人掺和在里面,一旦进程崩溃了,相关编程人员之间很容易互相扯皮,不利于维护安定团结的局面;另外,由于测试人员经常搞不清楚Bug属于谁,经常给错Bug,也容易制造人民内部矛盾。
  从上面可以看出来,相对细的进程颗粒度能够避免一些管理上的麻烦。由于XXX经常教导我们:"稳定压倒一切",所以该优点列第一条。
  2、健壮性、容错性
  一般来说,开发人员的水平参差不齐,优秀的毕竟是少数(具体参见"二八原理系列"的帖子)。所以难免会有菜鸟程序员搞出低级错误,而有些低级错误是致命的,会导致进程的崩溃。
  如果你是以业务逻辑划分进程,一个业务逻辑的进程崩溃,对其它业务逻辑的影响不大(除非是该业务逻辑的依赖方);因此就不会出现"注2"提到的问题。
  3、分布式
  我常碰见的分布式部署需求,一般都是按照业务逻辑的维度来划分。比如系统中有一个认证模块,里面包含有敏感的用户认证信息。这时候客户就会要求把该模块单独部署在一台经过安全加固的主机中(以防阶级敌人搞破坏)。
  如果是以业务逻辑为单位划分进程,要满足上述的部署需求就相对容易了(只要再配合恰当的进程间通讯机制,下面会提到)。
  另外,支持分布式部署还可以顺带解决性能问题。比如某个业务逻辑模块特别消耗硬件资源(比如内存、CPU、硬盘、带宽),就可以把它拿出去单独放一台机器上跑。
  4、跨编程语言
  这个好处可能很多人容易忽略。一般来说,每个编程语言都有各自的优缺点。如果你通过业务逻辑划分进程,就可以根据不同的业务逻辑的特点来选择合适的编程语言。
  比如:对于性能敏感的模块,我就使用C++搞定;而对于一些业务逻辑密集型的模块,则使用Java或Python开发。

  ★进程间通讯(以下简称IPC)问题
  既然不可能把整个系统放入一个进程,那就必然会碰到IPC的问题。下面就来说一下该如何选择IPC。
  各种操作系统里面,有很多稀奇古怪的IPC类型。由于要考虑跨平台,首先砍掉一批(关于IPC的跨平台问题,我在"跨平台开发"系列中会提到)。剩下的IPC类型中,能够进行数据传输的IPC就不多了,主要有如下几种:套接字(以下简称Socket)、共享内存、管道、文件。
  其中Socket是我强烈推荐的IPC方式,理由如下:使用Socket可以天然地支持分布式部署;使用Socket可以比较容易地实现多种编程语言的混合(比如C++、Java、Python、Flex都支持Socket);使用Socket还可以省掉了一大坨"锁操作"的代码。

  列位看官中,或许有人在担心Socket的性能问题,其实大可不必多虑。当两个进程在本机上进行Socket通讯时,由于可以使用localhost环回地址,数据不用经过物理网卡,操作系统内核还可以进行某些优化。这种情况下,Socket相对其它几种IPC机制,不会有太大的性能偏差。
  最后再补充一下,Socket方式也可以有效防止扯皮问题。举个例子:张三写了一个进程A,李四写了一个进程B,进程A通过Socket方式发数据给进程B。突然有一天,两个进程的通讯出故障了。然后张三就说是李四接收数据出错;李四就说张三发送数据出错。这时候怎么办捏?很简单,随便找个Sniffer软件当场抓一下数据包并Dump出来看,问题就水落石出了。


  ★为啥还要线程?
  上面说了这么多进程的好处,有同学要问了:"那线程有什么用捏?"总的来说,使用线程出于两方面的考虑:性能因素和编码方便。
  1、性能因素
  由于某些操作系统(比如Windows)中的进程比较重型,如果频繁创建进程或者创建大量进程,会导致操作系统的负载过高。举例如下:
  假设你要开发一个类似Web Server的应用。你针对每一个客户端请求创建一个对应的进程用于进行数据交互(是不是想起了古老的CGI :-)。一旦这个系统扩容,用户的并发连接数一增加,你的应用立马死翘翘。
  上面的例子表明,跨平台软件系统的进程数要保持相对稳定。如果你的进程数会随着某些环境因素呈线性增长,那就相当不妙了。而根据业务逻辑的单元划分进程,顺便能达到"进程数的相对稳定"的效果。
  2、编码方面
  由于业务逻辑内部的数据耦合比较紧密。如果业务逻辑内部的并发也用进程来实现,就会导致大量的IPC编码(任意两个进程之间只要有数据交互,就得写一坨IPC代码)。这会让相关的编程人员怨声载道。

  写到这里,看看篇幅有点超,就此打住。大伙儿如有不同看法,请到评论中拍砖。
---------------------------------------------------
  注1
  所谓"全部用进程",就是所有的并发都使用进程实现(因此每个进程只有一个线程)。这种设计在某些平台上(比如Windows)会导致严重的性能问题。

  注2
  所谓"全部用线程",就是所有的并发都使用线程实现(因此整个系统只有一个进程)。这种设计的健壮性极差(一个致命错会导致整个系统崩溃),而且更别提分布部署了。

--
刘未鹏(pongba)
Blog | Mind Hacks
http://mindhacks.cn
TopLanguage
http://groups.google.com/group/pongba



网易邮箱,中国第一大电子邮件服务商

sagasw

unread,
Feb 22, 2009, 7:29:15 PM2/22/09
to pon...@googlegroups.com
不错,不过还可以有这样更武断的办法:windows程序员,就学习多线程编程,少用多进程;linux程序员,ipc或者rpc那是必然要学的。



2009/2/22 pongba <pon...@gmail.com>

taodm

unread,
Feb 22, 2009, 8:10:14 PM2/22/09
to TopLanguage

怎么看都是上erlang的好场合。
至少,erlang的超轻量级进程,单台pc轻松支持100万个进程,就已经让这个主题不值得讨论了。

Jeffrey Zhao

unread,
Feb 22, 2009, 8:35:24 PM2/22/09
to pon...@googlegroups.com
在windows中“创建”和“销毁”进程的代价很昂贵,不是进程间通信很昂贵(当然可能也比进程内通信要昂贵)。
 
使用进程间通信,不代表需要创建销毁大量线程。
 
 
Jeffrey Zhao

From: sagasw
Sent: Monday, February 23, 2009 8:29 AM
Subject: [TopLanguage] Re: 进程还是线程?这是个问题! by 编程随想

不错,不过还可以有这样更武断的办法:windows程序员,就学习多线程编程,少用多进程;linux程序员,ipc或者rpc那是必然要学的。



2009/2/22 pongba <pon...@gmail.com>
还记得列表里面以前争吵过的进程vs线程的问题吗?

来自: http://program-think.blogspot.com/2009/02/multi-process-vs-multi-thread.html

  就像莎士比亚的"To be, or not to be, that is the question"始终困扰着哈姆雷特,对于"进程还是线程?"这个问题,也经常困扰着那些进行软件架构设计的家伙。所以今天打算聊一下我对这个问题的体会。假如你还搞不清楚线程和进程的区别,请先找本操作系统原理的书好好拜读一下,再回来看帖。

  由于这个问题很容易引发口水战,事先声明如下:多进程和多线程,无法一概而论地说谁比谁好。因此本帖主要描述特定场景(与我所负责的产品相关)下,进程和线程的权衡经验,仅供大伙儿参考。
  由于特定场景是本帖讨论的前提,先说说我目前负责的产品的特点:业务逻辑比较复杂、业务数据量比较大、对数据实时处理的性能要求比较高、对健壮性和安全性要求比较高、要求跨平台(包括操作系统、数据库)、某些情况下需要分布部署。
  上面说了一大堆,其实有不少的应用系统符合上述特点,比如:某些游戏服务器、某些金融方面的业务系统、某些电子商务系统等等。如果你正在从事的是类似的应用系统的设计,希望我下面介绍的经验对你有帮助。

  ★进程颗粒度问题
  大伙儿应该明白,进程和线程都是处理并发(concurrency)的手段。对于上述这种比较复杂的系统,如果你企图全部用进程(见注1)或者全部用线程(见注2)来处理并发,估计会死得很难看。所以,关键问题就是如何在进程和线程之间进行平衡(也就是确定进程颗粒度的问题)。
  我个人建议,尽量以业务逻辑的单元来划分进程。这样做的好处有如下几点:
  1、避免扯皮
  一般来说,某个固定业务逻辑的开发人员也是相对固定的。如果业务逻辑对应的某个进程崩溃了,测试人员容易快速定位肇事者,然后直接提交Bug给他/她。
  反之,一个进程搞得太庞大,N多人掺和在里面,一旦进程崩溃了,相关编程人员之间很容易互相扯皮,不利于维护安定团结的局面;另外,由于测试人员经常搞不清楚Bug属于谁,经常给错Bug,也容易制造人民内部矛盾。
  从上面可以看出来,相对细的进程颗粒度能够避免一些管理上的麻烦。由于XXX经常教导我们:"稳定压倒一切",所以该优点列第一条。
  2、健壮性、容错性
  一般来说,开发人员的水平参差不齐,优秀的毕竟是少数(具体参见"二八原理系列"的帖子)。所以难免会有菜鸟程序员搞出低级错误,而有些低级错误是致命的,会导致进程的崩溃。
  如果你是以业务逻辑划分进程,一个业务逻辑的进程崩溃,对其它业务逻辑的影响不大(除非是该业务逻辑的依赖方);因此就不会出现"注2"提到的问题。
  3、分布式
  我常碰见的分布式部署需求,一般都是按照业务逻辑的维度来划分。比如系统中有一个认证模块,里面包含有敏感的用户认证信息。这时候客户就会要求把该模块单独部署在一台经过安全加固的主机中(以防阶级敌人搞破坏)。
  如果是以业务逻辑为单位划分进程,要满足上述的部署需求就相对容易了(只要再配合恰当的进程间通讯机制,下面会提到)。
  另外,支持分布式部署还可以顺带解决性能问题。比如某个业务逻辑模块特别消耗硬件资源(比如内存、CPU、硬盘、带宽),就可以把它拿出去单独放一台机器上跑。
  4、跨编程语言
  这个好处可能很多人容易忽略。一般来说,每个编程语言都有各自的优缺点。如果你通过业务逻辑划分进程,就可以根据不同的业务逻辑的特点来选择合适的编程语言。
  比如:对于性能敏感的模块,我就使用C++搞定;而对于一些业务逻辑密集型的模块,则使用Java或Python开发。

  ★进程间通讯(以下简称IPC)问题
  既然不可能把整个系统放入一个进程,那就必然会碰到IPC的问题。下面就来说一下该如何选择IPC。
  各种操作系统里面,有很多稀奇古怪的IPC类型。由于要考虑跨平台,首先砍掉一批(关于IPC的跨平台问题,我在"跨平台开发"系列中会提到)。剩下的IPC类型中,能够进行数据传输的IPC就不多了,主要有如下几种:套接字(以下简称Socket)、共享内存、管道、文件。
  其中Socket是我强烈推荐的IPC方式,理由如下:使用Socket可以天然地支持分布式部署;使用Socket可以比较容易地实现多种编程语言的混合(比如C++、Java、Python、Flex都支持Socket);使用Socket还可以省掉了一大坨"锁操作"的代码。
  列位看官中,或许有人在担心Socket的性能问题,其实大可不必多虑。当两个进程在本机上进行Socket通讯时,由于可以使用localhost环回地址,数据不用经过物理网卡,操作系统内核还可以进行某些优化。这种情况下,Socket相对其它几种IPC机制,不会有太大的性能偏差。
  最后再补充一下,Socket方式也可以有效防止扯皮问题。举个例子:张三写了一个进程A,李四写了一个进程B,进程A通过Socket方式发数据给进程B。突然有一天,两个进程的通讯出故障了。然后张三就说是李四接收数据出错;李四就说张三发送数据出错。这时候怎么办捏?很简单,随便找个Sniffer软件当场抓一下数据包并Dump出来看,问题就水落石出了。

Program Thinker

unread,
Feb 22, 2009, 9:01:14 PM2/22/09
to pon...@googlegroups.com
to sjinny
对于那个类CGI的例子,我只是故意举一个极端的情形来说明"不要让进程数随环境因素呈线性增长(当然更别提指数增长了)"
我原文中忘记提醒一下"也别让线程数随环境因素呈线性增长",我待会儿在Blog中补充一下。
其实我也比较认同pool的做法。

至于适合多线程的场合,除了你提到的:"线程之间需要交换大量的数据,
并且无法或难以使用共享内存来实现交换。",我觉得还有其它情况也适合线程,举例如下:
例1
某进程主要负责某业务逻辑的处理,计算过程中需要不定期地从外部(比如DB、配置文件)载入某些数据参与业务逻辑处理。这时候可以用两个线程:一个主要进行处理,另一个阻塞等待某个外部的通知(比如信号量)。
例2
还有一种情况涉及到进程的反身逻辑。比如需要某个监控进程来监控其它进程的运行情况。这时候监控进程内部我倾向使用线程来监控其它进程。


2009/2/22 sjinny <sji...@163.com>

恩,对这个话题很感兴趣。
其实一开始看到"健壮"、"安全"、"分布部署"这些词的时候我就知道了,作者会使用进程来实现这些,而线程仅仅只是一种性能优化的手段。从我的角度来看,这时线程机制的作用就只是锦上添花而已,而进程机制则成为整个系统的支柱。
对里面提到的两个问题的看法:
1.使用线程进行性能优化的问题
按照文中的描述,使用线程来做性能优化而不是使用进程来做性能优化,是因为一个新的用户session会使用一个新的进程来处理,这样用户多的时候性能就会成为一个问题,而线程比进程更加轻便,所以使用了线程来做优化。但是线程的轻便只是相对于进程而言的,如果真的是一个用户连接对应一个线程,那么这个系统的承载能力仍然非常有限。
想起我以前开始做网络模块的时候,一开始看到的提供并发能力的方案就两种:多进程和多线程。当后来搞明白了select、poll和epoll的时候,越来越觉得使进程数或线程数与用户访问数直接相关是很糟糕的做法,因为你很难假设以后用户访问会不会增加以及增加到什么程度,而进程或线程则一直都是操作系统中昂贵的资源。所以文中举的那个用线程做性能优化的例子并不合适,那个问题我觉得还是用异步的方式会更好些。
性能优化时,使用线程比进程更合适的情况我现在只能想到这一种:线程之间需要交换大量的数据,并且无法或难以使用共享内存来实现交换。
2.使用线程来避免IPC时的繁琐操作的问题
我觉得IPC并不必然是繁琐的,其实我觉得对于参与通信的进程来说IPC应该是透明的,这样逻辑功能直接的交互不仅不会导致"大量的IPC编码",甚至不会导致任何IPC编码。
就简单的IPC来说,其实已经做到了透明,比如管道,对于管线上的一环来说,它只是读写stdio而已,并不需要做任何特殊的处理,可能一个进程开发的时候完全就是一个独立的程序而不是作为一个分布式系统的一部分,之后使用了netcat和管道就加入了一个分布式系统,而这个进程不需要为此做任何修改。
我这段时间的尝试就是做出一个程序,它能够为其他进程提供透明的IPC服务,不仅能支持1对1的通信,而且能支持m对n的通信。以前做过的网络模块,不管怎么样设计,使用的时候仍然需要使用特定的头文件、库文件和函数调用,甚至会影响到使用它的程序的设计,这次这个东西的目标就是它的使用不会影响使用者自己的设计。

----------------
编程随想
progra...@gmail.com
http://program-think.blogspot.com

Program Thinker

unread,
Feb 22, 2009, 9:16:00 PM2/22/09
to pon...@googlegroups.com
to taodm
我当初设计这个产品的时候,erlang还没有现在这么出名。现在倒是可以考虑一下,或许可以在某个合适的模块试点一下。
不过,我估计很多其它模块未必合适用erlang,这点我在"4、跨编程语言"中有提到。

2009/2/23 taodm <tao.do...@zte.com.cn>


怎么看都是上erlang的好场合。
至少,erlang的超轻量级进程,单台pc轻松支持100万个进程,就已经让这个主题不值得讨论了。

Jeffrey Zhao

unread,
Feb 22, 2009, 9:19:36 PM2/22/09
to pon...@googlegroups.com
此进程非彼进程。


Jeffrey Zhao

--------------------------------------------------
From: "taodm" <tao.do...@zte.com.cn>
Sent: Monday, February 23, 2009 9:10 AM
To: "TopLanguage" <pon...@googlegroups.com>


Subject: [TopLanguage] Re: 进程还是线程?这是个问题! by 编程随想

>

Program Thinker

unread,
Feb 22, 2009, 9:31:38 PM2/22/09
to pon...@googlegroups.com
to taodm
我曾经听说过,erlang的进程是语言本身的逻辑概念,不是物理的进程 :-)
我想说的是:erlang虽然有超轻量级"进程",不过我个人感觉只有个别合适的模块可以考虑用erlang来试点。

2009/2/23 Jeffrey Zhao <je...@live.com>



--

Changsheng Jiang

unread,
Feb 22, 2009, 9:42:10 PM2/22/09
to pon...@googlegroups.com
记得以前看过哪儿说 Xserver 就没有使用线程或进程. 使用线程只是某种程度上编程方便. 早期有些操作系统的有IO锁粒度太大不可调的问题, 现在基本都没有了.

select, epoll 好像不是可跨平台的. 涉及到部署到多台机子, 似乎只能用进程.

关于频繁写IPC, 以为进程之间应该只定义数据格式, 不定义数据交换的方法. 数据交换方法独立存在.


Yours Sincerely,
Changsheng Jiang

Program Thinker

unread,
Feb 22, 2009, 9:55:12 PM2/22/09
to pon...@googlegroups.com
如果公司里面有很成熟且方便易用的IPC库,可以比较透明地封装IPC相关操作,那线程在"方便编码"的某些优势就削弱了。或许就能够做到楼上说的"只定义数据格式, 不定义数据交换的方法"。

2009/2/23 Changsheng Jiang <jiang...@gmail.com>

sagasw

unread,
Feb 22, 2009, 11:34:09 PM2/22/09
to pon...@googlegroups.com
google的protocol buffer可以作为跨进程跨平台的一个选择,相比xml要快速很多(自称)。


2009/2/23 Program Thinker <progra...@gmail.com>

sjinny

unread,
Feb 23, 2009, 10:34:55 AM2/23/09
to pon...@googlegroups.com
erlang能作为一种IPC机制为其他任意语言编写的独立程序提供通信支持吗?


在2009-02-23,taodm <tao.do...@zte.com.cn> 写道:
>
>怎么看都是上erlang的好场合。
>至少,erlang的超轻量级进程,单台pc轻松支持100万个进程,就已经让这个主题不值得讨论了。



网易邮箱,中国第一大电子邮件服务商

sjinny

unread,
Feb 23, 2009, 10:45:21 AM2/23/09
to pon...@googlegroups.com
恩,关于多线程的适用场合的问题:
关于例1:
你说的情况似乎比较类似于AIO,我觉得这个其实也可以用poll模型来搞定,当然做一个专门的数据存取进程也是一种方案,实际上就是针对具体的需求实现一个AIO服务进程。后者可以使得逻辑处理部分与数据载入部分的耦合比较小,也不需要涉及线程控制,如果做得好的话,可能连IPC涉及得也会非常少甚至不涉及。也许某种角度看,把颗粒度分到这么细似乎有点小题大作了,不过另一个角度看,其实完全可以把这个AIO服务进程做得通用些,使其成为逻辑处理进程的驱动者,运行时只需要逻辑处理进程把所需的数据描述给AIO进程,然后AIO进程会把所需的数据按照所需的顺序组织好再发送给逻辑处理进程,逻辑处理进程只需要阻塞地读取、顺序地处理。好像YY得有些远了,呵呵。
例2:
我对进程监控不太了解,不知道有什么好办法?

在2009-02-23,"Program Thinker" <progra...@gmail.com> 写道:
to sjinny
对于那个类CGI的例子,我只是故意举一个极端的情形来说明"不要让进程数随环境因素呈线性增长(当然更别提指数增长了)"
我原文中忘记提醒一下"也别让线程数随环境因素呈线性增长",我待会儿在Blog中补充一下。
其实我也比较认同pool的做法。

至于适合多线程的场合,除了你提到的:"线程之间需要交换大量的数据,
并且无法或难以使用共享内存来实现交换。",我觉得还有其它情况也适合线程,举例如下:
例1
某进程主要负责某业务逻辑的处理,计算过程中需要不定期地从外部(比如DB、配置文件)载入某些数据参与业务逻辑处理。这时候可以用两个线程:一个主要进行处理,另一个阻塞等待某个外部的通知(比如信号量)。
例2
还有一种情况涉及到进程的反身逻辑。比如需要某个监控进程来监控其它进程的运行情况。这时候监控进程内部我倾向使用线程来监控其它进程。





网易邮箱,中国第一大电子邮件服务商

sjinny

unread,
Feb 23, 2009, 10:46:37 AM2/23/09
to pon...@googlegroups.com
select是跨平台的吧,epoll倒不是。

网易邮箱,中国第一大电子邮件服务商

sjinny

unread,
Feb 23, 2009, 10:48:04 AM2/23/09
to pon...@googlegroups.com
我对透明的IPC机制也很感兴趣,不知道Program Thinker对这方面有没有什么看法?


 

在2009-02-23,"Program Thinker" <progra...@gmail.com> 写道:

网易邮箱,中国第一大电子邮件服务商

sagasw

unread,
Feb 23, 2009, 8:48:06 PM2/23/09
to pon...@googlegroups.com
不认为可以,速度是大问题。
如果有类似通讯支持,应该是c实现,因为大部分语言都支持与c进行语言级别的通信。既可以通用又可以保证速度。


2009/2/23 sjinny <sji...@163.com>

Lai Jiangshan

unread,
Feb 24, 2009, 9:09:28 AM2/24/09
to pon...@googlegroups.com, sjinny
多核时代, 多进程多线程一般优于aio, select,epoll (io超级密集型应用除外)

ps, erlang 的多线程这么轻不会全是绿色的吧. 如果不是, 他怎么做到高效的m->n映射

2009/2/23 sjinny <sji...@163.com>:

Program Thinker

unread,
Feb 24, 2009, 10:39:03 AM2/24/09
to pon...@googlegroups.com
to sjinny
以前曾经用ACE做过一个,不过只能用于C++模块,感觉不太爽。大伙儿如果对这个话题感兴趣,单独开一个帖子聊 :-)
另外,当时设计产品的时候曾经考虑过用ICE(号称支持跨语言、跨平台),可惜后来没用成。不知道论坛里有没有人用过这玩意儿,介绍一下。

2009/2/23 sjinny <sji...@163.com>
我对透明的IPC机制也很感兴趣,不知道Program Thinker对这方面有没有什么看法?
 

在2009-02-23,"Program Thinker" <progra...@gmail.com> 写道:
如果公司里面有很成熟且方便易用的IPC库,可以比较透明地封装IPC相关操作,那线程在"方便编码"的某些优势就削弱了。或许就能够做到楼上说的"只定义数据格式, 不定义数据交换的方法"。

sjinny

unread,
Feb 24, 2009, 9:00:24 PM2/24/09
to pon...@googlegroups.com
关于透明的IPC,我现在有点初步的想法,可能这段时间会想办法往前推进一点。又或者先把现有的整理出来讨论讨论?
 
ICE我曾经学过一点,但是发现用起来其实还是麻烦。最大的问题就是不透明,我想这可能是个通病了。而且虽然号称比corba更容易学,但感觉还是要学很多东西。


网易邮箱,中国第一大电子邮件服务商

David Gao

unread,
Mar 1, 2009, 5:05:42 AM3/1/09
to pon...@googlegroups.com
erlang能作为一种IPC机制为其他任意语言编写的独立程序
提供通信支持吗?

我认为是可以的。
Erlang自身为包的读取和解析提供了很好的支持。至少我目前做的,用Erlang为C++提供支持可以实现。:)


2009/2/25 sjinny <sji...@163.com>



--
David Gao

sjinny

unread,
Mar 1, 2009, 9:35:38 AM3/1/09
to pon...@googlegroups.com
恩……具体形式是什么样的呢?比如说功能进程是否需要遵循IPC机制的数据协议,比如输入输出都是指定格式的消息?


网易邮箱,中国第一大电子邮件服务商

qiaojie

unread,
Mar 1, 2009, 10:54:53 AM3/1/09
to TopLanguage
不太同意进程比线程更健壮的说法,如果是用多进程的话一般都是流水线的设计,其中某个进程crash了,那么整个流水线就block在这个进程上了,就
算其他进程都正常,整个服务还是不能正常工作的。另外用了多进程的话,因为进程之间有依赖性,整个服务的启动、关闭、维护都会变得相对困难,更谈不上健
壮了。
采用多线程还是多进程主要还是取决与你的应用。多线程的优点在于线程之间可以共享内存,如果你的应用有大量状态需要共享,那么多线程就提供了高效且便利
的机制来存取这些状态,而用多进程的话如果要共享状态就会变得非常昂贵而可能严重的拖跨性能。多进程的好处则是可以部署到多个的物理服务器上,实现更好
的伸缩性,这是多线程做不到的。
对于未来并行程序的发展,个人还是倾向于多线程会占据主导,一方面CPU会集成越来越多的核心,Intel的Larrabee可以集成32个核心,同时
运行上千个线程,另一方面GPU也开始逐步渗透到通用计算领域,CUDA是一个很好的并行计算的平台,而最新出的OpenCL标准则不但支持GPU也可
以支持CPU,发展的好的话有希望把GPU和CPU的并行计算统一到一个框架里去。由于所有这些框架都是基于多线程的,将来对于并行程序的研究也必然会
在多线程上展开。

On Feb 22, 9:06 pm, pongba <pon...@gmail.com> wrote:
> *还记得列表里面以前争吵过的进程vs线程的问题吗?*
>
> 来自:http://program-think.blogspot.com/2009/02/multi-process-vs-multi-thre...


>
> 就像莎士比亚的"To be, or not to be, that is the
> question"始终困扰着哈姆雷特,对于"进程还是线程?"这个问题,也经常困扰着那些进行软件架构设计的家伙。所以今天打算聊一下我对这个问题的体
> 会。假如你还搞不清楚线程和进程的区别,请先找本操作系统原理的书好好拜读一下,再回来看帖。

> 由于这个问题很容易引发口水战,事先声明如下:多进程和多线程,无法一概而论地说谁比谁好。因此本帖主要描述*特定场景*
> (与我所负责的产品相关)下,进程和线程的权衡经验,仅供大伙儿参考。
> 由于特定场景是本帖讨论的前提,先说说我目前负责的产品的特点:业务逻辑比较复杂、业务数据量比较大、对数据*实时*


> 处理的性能要求比较高、对健壮性和安全性要求比较高、要求跨平台(包括操作系统、数据库)、某些情况下需要分布部署。

> 上面说了一大堆,其实有不少的应用系统符合上述特点,比如:某些游戏服务器、某些金融方面的业务系统、某些电子商务系统等等。如果你正在从事的是类似的应用系统-的设计,希望我下面介绍的经验对你有帮助。
>
> ★进程颗粒度问题
> 大伙儿应该明白,进程和线程都是处理并发(concurrency)的手段。对于上述这种比较复杂的系统,如果你企图全部用进程(见注1<http://program-think.blogspot.com/#comment1>
> )或者全部用线程(见注2 <http://program-think.blogspot.com/#comment2>


> )来处理并发,估计会死得很难看。所以,关键问题就是如何在进程和线程之间进行平衡(也就是确定进程颗粒度的问题)。

> 我个人建议,尽量*以业务逻辑的单元来划分进程*。这样做的好处有如下几点:


> 1、避免扯皮
> 一般来说,某个固定业务逻辑的开发人员也是相对固定的。如果业务逻辑对应的某个进程崩溃了,测试人员容易快速定位肇事者,然后直接提交Bug给他/她。

> 反之,一个进程搞得太庞大,N多人掺和在里面,一旦进程崩溃了,相关编程人员之间很容易互相扯皮,不利于维护安定团结的局面;另外,由于测试人员经常搞不清楚B-ug属于谁,经常给错Bug,也容易制造人民内部矛盾。
> 从上面可以看出来,*相对*细的进程颗粒度能够避免一些管理上的麻烦。由于XXX经常教导我们:"稳定压倒一切",所以该优点列第一条。
> 2、健壮性、容错性
> 一般来说,开发人员的水平参差不齐,优秀的毕竟是少数(具体参见"二八原理系列<http://program-think.blogspot.com/2009/02/80-20-principle-0-overview....>
> "的帖子)。所以难免会有菜鸟程序员搞出低级错误,而有些低级错误是致命的,会导致进程的崩溃。
> 如果你是以业务逻辑划分进程,一个业务逻辑的进程崩溃,对其它业务逻辑的影响不大(除非是该业务逻辑的依赖方);因此就不会出现"注2<http://program-think.blogspot.com/#comment2>
> "提到的问题。

Program Thinker

unread,
Mar 1, 2009, 9:26:59 PM3/1/09
to pon...@googlegroups.com
楼上的同学

关于进程的流水线问题,其实不一定如你所说的这么悲观。
我举例如下:

数据采集 ==> DB ==> 数据分析 ==> DB ==> 数据展示

假设有这么一个业务流程,其中数据采集、数据分析、数据展示都用进程实现。
如果某个进程崩溃,只要由专门的进程监控模块把崩溃的进程重新启动,对于其它进程的影响很小。
另外,即使进程之间不是通过DB,而是通过诸如socket方式进行数据交互,只有有专门的进程监控机制,也很容易恢复过来。


关于多线程的优点,其实我原文中已经提到。
对于数据耦合比较紧密的情况,我认为线程会比较方便。


2009/3/1 qiaojie <qia...@gmail.com>

不太同意进程比线程更健壮的说法,如果是用多进程的话一般都是流水线的设计,其中某个进程crash了,那么整个流水线就block在这个进程上了,就
算其他进程都正常,整个服务还是不能正常工作的。另外用了多进程的话,因为进程之间有依赖性,整个服务的启动、关闭、维护都会变得相对困难,更谈不上健
壮了。
采用多线程还是多进程主要还是取决与你的应用。多线程的优点在于线程之间可以共享内存,如果你的应用有大量状态需要共享,那么多线程就提供了高效且便利
的机制来存取这些状态,而用多进程的话如果要共享状态就会变得非常昂贵而可能严重的拖跨性能。

--

Bennie

unread,
Mar 1, 2009, 10:02:10 PM3/1/09
to TopLanguage
进程的崩溃和重启动远没有想象的那么简单,也需要一套复杂的实现来保证。要不就不会有系统管理员这个职位存在。
进程优于线程的只有存取边界和跨机器部署,隐形的优势是防止程序员抻面条。想用个全局就用全局,全无顾虑。

On Mar 2, 10:26 am, Program Thinker <program.th...@gmail.com> wrote:
> 楼上的同学
>
> 关于进程的流水线问题,其实不一定如你所说的这么悲观。
> 我举例如下:
>
> 数据采集 ==> DB ==> 数据分析 ==> DB ==> 数据展示
>
> 假设有这么一个业务流程,其中数据采集、数据分析、数据展示都用进程实现。

> 如果某个进程崩溃,只要由专门的*进程监控*模块把崩溃的进程重新启动,对于其它进程的影响很小。


> 另外,即使进程之间不是通过DB,而是通过诸如socket方式进行数据交互,只有有专门的进程监控机制,也很容易恢复过来。
>
> 关于多线程的优点,其实我原文中已经提到。
> 对于数据耦合比较紧密的情况,我认为线程会比较方便。
>

> 2009/3/1 qiaojie <qiao...@gmail.com>


>
> > 不太同意进程比线程更健壮的说法,如果是用多进程的话一般都是流水线的设计,其中某个进程crash了,那么整个流水线就block在这个进程上了,就
> > 算其他进程都正常,整个服务还是不能正常工作的。另外用了多进程的话,因为进程之间有依赖性,整个服务的启动、关闭、维护都会变得相对困难,更谈不上健
> > 壮了。
> > 采用多线程还是多进程主要还是取决与你的应用。多线程的优点在于线程之间可以共享内存,如果你的应用有大量状态需要共享,那么多线程就提供了高效且便利
> > 的机制来存取这些状态,而用多进程的话如果要共享状态就会变得非常昂贵而可能严重的拖跨性能。
>
> --
> ----------------
> 编程随想

> program.th...@gmail.comhttp://program-think.blogspot.com

Program Thinker

unread,
Mar 1, 2009, 10:55:56 PM3/1/09
to pon...@googlegroups.com
具体要看 “复杂的实现” 到底有多复杂。如果衡量下来,“复杂的实现” 产生的成本不太大,那用进程还是挺合算的(我以前做的系统就属于这种情况)。
毕竟进程的优势,楼上的同学也点出来了。而且有些优势(比如跨机器)线程在技术上无法取代。

另外,楼上的同学能否介绍一下,之前碰到的由于 “进程崩溃和重启动” 导致的复杂实现大概是什么样子的?

2009/3/2 Bennie <ZhaoY...@gmail.com>

进程的崩溃和重启动远没有想象的那么简单,也需要一套复杂的实现来保证。要不就不会有系统管理员这个职位存在。
进程优于线程的只有存取边界和跨机器部署,隐形的优势是防止程序员抻面条。想用个全局就用全局,全无顾虑。

sjinny

unread,
Mar 1, 2009, 10:56:30 PM3/1/09
to pon...@googlegroups.com
如果某个进程崩溃了,只需要重启它就可以了,但是如果某个线程崩了,重启是否会更困难?甚至直接把整个进程害死?
虽然进程之间有依赖性,但是启动顺序应该没有什么大的关系,连不上依赖进程就等着呗,反正都启动之后就没问题了。
进程的健壮性还包括了一个进程的bug不会直接影响到其他进程,因为有内存访问保护。如果进程不能带来健壮性,那么现在的操作系统是为了什么而发展出带内存访问保护的多进程特性的?
共享内存往往不是个优点:它*可能*带来性能上的提高,却*必然*提高复杂度,并且会妨碍模块分离到不同的内存空间中(比如两台电脑)。
如果两个模块有大量状态要共享,却需要有自己的CPU资源入口(不需要其他人来调用它,它可以自主运行),那么我怀疑设计有问题:耦合太严重了……这种情况下使用线程来优化性能只是解决了次要的问题:不管性能多高,高耦合的设计会使它走不了多远的……实际上,多进程提供的伸缩性可以更容易地提高性能,你可以很容易的购买10台1GHzCPU的电脑,但是你能买到一台10GHzCPU的电脑吗?如不是10*1G,而是100*2G呢?当然,现在有多核CPU,但是,是一个CPU上集成大量内核容易,还是一个高速网络里连上大量电脑更容易呢?

网易邮箱,中国第一大电子邮件服务商

肖海彤

unread,
Mar 1, 2009, 11:05:22 PM3/1/09
to TopLanguage
不从设计阶段就考虑崩溃检测和重启动, 那么运维阶段的处理当然很复杂.

qiaojie

unread,
Mar 1, 2009, 10:40:38 PM3/1/09
to pon...@googlegroups.com
想的太简单了,容错和灾难恢复需要非常仔细的考虑和设计,不是简单的重启一下进程就完事的。你要考虑如何恢复进程内的状态到上一次crash的状态上,依赖他的进程要考虑连接的重建,还要考虑先前发送的任务的取消或重试,在很多情况下状态是恢复不过来的,只有重启整个服务。而且进程的crash也不是你所想的那种程序BUG引起的内存越界之类的错误,首先的假设是程序本身没有错误,而是运行环境造成的crash,比如内存或者硬盘耗尽,网络故障,断电或者硬件故障等等



2009/3/2 Program Thinker <progra...@gmail.com>

sjinny

unread,
Mar 1, 2009, 11:25:15 PM3/1/09
to pon...@googlegroups.com
的确,会有恢复不过来的情况,但是如果遇到了这种情况,重启整个服务就能够恢复了吗?该丢失的东西还是丢失了……
就一个流水线而言,如果可靠性很重要,最简单的就是热备份,而线程要做热备份的话该怎么做呢?
如果一个进程本身没有状态,那么恢复就很简单;如果有,那么可以定期存储,然后在输入的位置进行输入记录,在重启的时候重放输入……
如果一点数据损失都不能承受,那就热备份好了……
进程机制本身当然不可能什么都抵挡得住,不过相比于线程我觉得进程还是更加健壮一些。


网易邮箱,中国第一大电子邮件服务商

Bennie

unread,
Mar 1, 2009, 11:33:07 PM3/1/09
to TopLanguage
运用线程就是"要死一起死",而多进程通常是"你死我不死",那么要花相当多的功夫在把功能组的状态维持到一个受控状态上。
复杂程度随着进程增加而线性或指数增长。所以多进程通常要预先设计一套机制来实现进程管理框架。

说到场景恢复问题和线程监视问题倒是进程和线程都存在的。

On Mar 2, 11:55 am, Program Thinker <program.th...@gmail.com> wrote:
> 具体要看 "复杂的实现" 到底有多复杂。如果衡量下来,"复杂的实现" 产生的成本不太大,那用进程还是挺合算的(我以前做的系统就属于这种情况)。
> 毕竟进程的优势,楼上的同学也点出来了。而且有些优势(比如跨机器)线程在技术上无法取代。
>
> 另外,楼上的同学能否介绍一下,之前碰到的由于 "进程崩溃和重启动" 导致的复杂实现大概是什么样子的?
>

> 2009/3/2 Bennie <ZhaoYin...@gmail.com>


>
> > 进程的崩溃和重启动远没有想象的那么简单,也需要一套复杂的实现来保证。要不就不会有系统管理员这个职位存在。
> > 进程优于线程的只有存取边界和跨机器部署,隐形的优势是防止程序员抻面条。想用个全局就用全局,全无顾虑。
>
> --
> ----------------
> 编程随想

> program.th...@gmail.comhttp://program-think.blogspot.com

sjinny

unread,
Mar 1, 2009, 11:41:30 PM3/1/09
to pon...@googlegroups.com
我说,不必“你跳我也跳”吧……如果要让进程做到“你宕我也宕”,那也不难吧,只要一个进程发现与依赖进程失去了联系,就自己宕掉……


网易邮箱,中国第一大电子邮件服务商

windstorm

unread,
Mar 2, 2009, 12:27:33 AM3/2/09
to pon...@googlegroups.com
没理解你说多线程和“多核”的“相互促进”的关系

CUDA个人理解是一个很大的SIMD,不是线程的概念

线程的本质问题,参见这篇文章

http://www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.html

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/1 qiaojie <qia...@gmail.com>:

qiaojie

unread,
Mar 2, 2009, 1:03:49 AM3/2/09
to pon...@googlegroups.com
线程和进程的本质区别在于存储模型。存储模型对于并行计算是非常重要的概念,决定了你可以做什么不可以做什么。只有多核出现之后,我们才有了可以共享内存的多个计算单元的硬件,多线程实现并行计算才会变得有价值,所以说是多核促成了多线程并行计算的发展,现在的CPU最多也就是4核8核,还显示不出什么威力,但如果像GPU那样同时运行上千个线程,那么威力就完全显示出来了。

另外CUDA也不是SIMD,GPU内部虽然有SIMD单元用来执行向量操作,但是CUDA每个执行绪有自己的分支和跳转,这个不是SIMD的范畴。




2009/3/2 windstorm <likunar...@gmail.com>

windstorm

unread,
Mar 2, 2009, 1:12:08 AM3/2/09
to pon...@googlegroups.com
传统的cluster不早就几千个线程了么,又不是什么稀罕的事情,看看IBM的深蓝不就是么。

共享内存的存储模型也不是新的概念,OpenMP就是一个可以在Cluster上做share memory programming的模型。

关于CUDA,虽然它能执行分支和跳转,但是所有线程必须必须执行同样的分支和跳转,如果线程处于不同的分支和跳转,他们会相互等待,对于大规模的数据并行这不是大问题,这也是为什么我认为它是一个SIMD的模型体现。但是对于细粒度的并行,比如instruction
level or task level的并行,CUDA就很难高效handle。

所以,我认为线程只是传统的串行计算机的模型,本质问题那篇paper也说了很多,现在有很多真正细粒度的programming
model,比如actor这种,我认为这些更加promising

qiaojie

unread,
Mar 2, 2009, 2:24:26 AM3/2/09
to pon...@googlegroups.com
你所说的cluster是超级计算机一类的大型计算机吧?上千万一台的东西对你来说居然都不算希罕玩意,你可以的.....反正我是没机会接触。共享内存当然不是什么新鲜概念,但是从理论到实用是要经过很长一段路要走的。
在CUDA里面每个线程可以有不同的分支顺序而不会互相等待,不然的话分支程序的效率将一塌糊涂了,建议你再好好的看一下CUDA的架构。
至于你所说的那篇文章,作者只是抱怨了一番多线程编程有多困难,但是却给不出更好的计算模型来(虽然他相信有),最多只是在多线程的基础上增加一些约束和抽象出一些更高层的概念来简化这些困难,但是本质上还是脱离不了多线程的。



2009/3/2 windstorm <likunar...@gmail.com>

jiang li

unread,
Mar 2, 2009, 2:56:40 AM3/2/09
to pon...@googlegroups.com
你们两个人的理解应该都有些问题。
“A computer cluster is a group of linked computers, working together closely so that in many respects they form a single computer.”,所以cluster应该是很多台机器,而不是一台机器。
至于OpenMP,它应该是不能用于cluster的,因为一般意义的cluster是不共享内存的。cluster常用的是MPI。

2009/3/2 qiaojie <qia...@gmail.com>

mryufeng

unread,
Mar 2, 2009, 5:03:36 AM3/2/09
to TopLanguage
erlang结合了线程和进程的优点 调度器和信的过的驱动用线程实现 port外部程序用进程来调动,这样既保证了cpu的利用,又能保证系统的稳定
性!

erlang非业余 mryufeng.javaeye.com

sjinny

unread,
Mar 2, 2009, 5:30:35 AM3/2/09
to pon...@googlegroups.com
如果我没记错的话,在多核出来之前就有一个主板插两个CPU了……


网易邮箱,中国第一大电子邮件服务商

sjinny

unread,
Mar 2, 2009, 5:34:31 AM3/2/09
to pon...@googlegroups.com
超级计算机往往不是“一台”……cluster也都不是“一台”,而是N多台计算机通过网络连接起来……


网易邮箱,中国第一大电子邮件服务商

sjinny

unread,
Mar 2, 2009, 5:40:00 AM3/2/09
to pon...@googlegroups.com
不懂erlang,所以看不明白里面的术语……:)

网易邮箱,中国第一大电子邮件服务商

windstorm

unread,
Mar 2, 2009, 11:20:41 AM3/2/09
to pon...@googlegroups.com
我没觉得我理解错了。

我说的Bluegene就是scale到cluster形式的,超级计算机没有不这么用的吧?

OpenMP有for cluster的啊:http://www.hpcwire.com/features/17884424.html

To qiaojie:你确定?你看看这篇文章

http://www.touchdreams.net/blog/2009/02/26/cuda-thread-warp-and-simt/

我很早以前看过CUDA的正式论文,也记得是这样的。也可能是我记错了。你的说法的出处?

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/2 jiang li <li.ji...@gmail.com>:

jiang li

unread,
Mar 2, 2009, 8:34:53 PM3/2/09
to pon...@googlegroups.com
"Intel is offering Cluster OpenMP*, which extends the OpenMP programming model to clusters"
sorry,我不知道intel出了一个扩展版本。
OpenMP的通信是基于共享内存的,一般cluster不具备这一点。Intel的这个版本将它扩展了,底层的实现应该是基于消息传递,然后模拟出共享内存的接口。所以对于开发人员好像还是在访问共享内存,但其实底层是消息传递机制。

2009/3/3 windstorm <likunar...@gmail.com>

amuseme

unread,
Mar 2, 2009, 9:14:10 PM3/2/09
to TopLanguage
用线程还是进程,这个问题大部分都取决于你当前的应用,多线程可能不是所有问题的最好的解决方法,也有可能产生负面的效率问题,如果程序像管道一样运
行,后一步的运行要前一步的结果,如果用多线程,那后一个线程会等待前一线程的结果才能开始运行。可能在二种情况下会用到多线程,1. 有大量同步的计
算可能在多个cpu上运行 2. 要执行大量I/O操作来提升吞吐量的时候,如果client/server架构,server要同时响应多个
client请求,提供大量的并行处理。记得google的浏览器chrome就是一个tab一个进程的方式还做的,而firefox就是所有tab都
在一个进程下,多个firefox的窗口(GUI)也是在同一进程下。

erlang语言把并发特性提升到了一个更好的层次,不过可能它的优势还是在于通讯方面。

On 3月3日, 上午9时34分, jiang li <li.jian...@gmail.com> wrote:
> "Intel is offering Cluster OpenMP*, which extends the OpenMP programming
> model to clusters"
> sorry,我不知道intel出了一个扩展版本。
> OpenMP的通信是基于共享内存的,一般cluster不具备这一点。Intel的这个版本将它扩展了,底层的实现应该是基于消息传递,然后模拟出共享内存的接口。所以对于开发人员好像还是在访问共享内存,但其实底层是消息传递机制。
>

> 2009/3/3 windstorm <likunarmstr...@gmail.com>


>
> > 我没觉得我理解错了。
>
> > 我说的Bluegene就是scale到cluster形式的,超级计算机没有不这么用的吧?
>
> > OpenMP有for cluster的啊:http://www.hpcwire.com/features/17884424.html
>
> > To qiaojie:你确定?你看看这篇文章
>
> >http://www.touchdreams.net/blog/2009/02/26/cuda-thread-warp-and-simt/
>
> > 我很早以前看过CUDA的正式论文,也记得是这样的。也可能是我记错了。你的说法的出处?
>
> > ----------------------------------------------------------------------------------
> > Yours Sincerely
> > Kun
>
> > blog:www.forwind.cn
>

> > 2009/3/2 jiang li <li.jian...@gmail.com>:


> > > 你们两个人的理解应该都有些问题。
> > > "A computer cluster is a group of linked computers, working together
> > closely
> > > so that in many respects they form a single
> > > computer.",所以cluster应该是很多台机器,而不是一台机器。
> > > 至于OpenMP,它应该是不能用于cluster的,因为一般意义的cluster是不共享内存的。cluster常用的是MPI。
>

> > > 2009/3/2 qiaojie <qiao...@gmail.com>


>
> > 你所说的cluster是超级计算机一类的大型计算机吧?上千万一台的东西对你来说居然都不算希罕玩意,你可以的.....反正我是没机会接触。共享内存当然不是什么新鲜概念,但是从理论到实用是要经过很长一段路要走的。
> > >> 在CUDA里面每个线程可以有不同的分支顺序而不会互相等待,不然的话分支程序的效率将一塌糊涂了,建议你再好好的看一下CUDA的架构。
>
> > 至于你所说的那篇文章,作者只是抱怨了一番多线程编程有多困难,但是却给不出更好的计算模型来(虽然他相信有),最多只是在多线程的基础上增加一些约束和抽象出一些更高层的概念来简化这些困难,但是本质上还是脱离不了多线程的。
>

> > >> 2009/3/2 windstorm <likunarmstr...@gmail.com>


>
> > >>> 传统的cluster不早就几千个线程了么,又不是什么稀罕的事情,看看IBM的深蓝不就是么。
>
> > >>> 共享内存的存储模型也不是新的概念,OpenMP就是一个可以在Cluster上做share memory programming的模型。
>
> > 关于CUDA,虽然它能执行分支和跳转,但是所有线程必须必须执行同样的分支和跳转,如果线程处于不同的分支和跳转,他们会相互等待,对于大规模的数据并行这不是大问题,这也是为什么我认为它是一个SIMD的模型体现。但是对于细粒度的并行,比如instruction
> > >>> level or task level的并行,CUDA就很难高效handle。
>
> > >>> 所以,我认为线程只是传统的串行计算机的模型,本质问题那篇paper也说了很多,现在有很多真正细粒度的programming
> > >>> model,比如actor这种,我认为这些更加promising
>
> > ----------------------------------------------------------------------------------
> > >>> Yours Sincerely
> > >>> Kun
>
> > >>> blog:www.forwind.cn
>

> > >>> 2009/3/1 qiaojie <qiao...@gmail.com>:


>
> > 线程和进程的本质区别在于存储模型。存储模型对于并行计算是非常重要的概念,决定了你可以做什么不可以做什么。只有多核出现之后,我们才有了可以共享内存的多个计算单元的硬件,多线程实现并行计算才会变得有价值,所以说是多核促成了多线程并行计算的发展,现在的CPU最多也就是4核8核,还显示不出什么威力,但如果像GPU那样同时运行上千个线程,那么威力就完全显示出来了。
>
> > 另外CUDA也不是SIMD,GPU内部虽然有SIMD单元用来执行向量操作,但是CUDA每个执行绪有自己的分支和跳转,这个不是SIMD的范畴。
>

> > >>> > 2009/3/2 windstorm <likunarmstr...@gmail.com>


>
> > >>> >> 没理解你说多线程和"多核"的"相互促进"的关系
>
> > >>> >> CUDA个人理解是一个很大的SIMD,不是线程的概念
>
> > >>> >> 线程的本质问题,参见这篇文章
>
> > >>> >>http://www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.html
>
> > ----------------------------------------------------------------------------------
> > >>> >> Yours Sincerely
> > >>> >> Kun
>
> > >>> >> blog:www.forwind.cn
>

> > >>> >> 2009/3/1 qiaojie <qiao...@gmail.com>:

> ...
>
> 阅读更多 >>

qiaojie

unread,
Mar 2, 2009, 9:55:36 PM3/2/09
to pon...@googlegroups.com
你说的这个是GPU内部的一种实现细节,GPU以wrap(32个线程为一个wrap)为执行单位,在一个wrap内,线程的各分支会被串行化,在wrap内线程的执行时间总是一致的,这可以看成是对线程调度的一种优化,使得线程调度的开销为0。但是同一时间里会有很多个wrap同时运行,而wrap之间的执行是独立的,不存在互相等待的问题。但是内部的这种实现机制不影响线程概念的完备性。



2009/3/3 windstorm <likunar...@gmail.com>

windstorm

unread,
Mar 2, 2009, 11:22:00 PM3/2/09
to pon...@googlegroups.com
To qiaojie:

第一,同一个SM只能执行一个wrap,在一个时间段内。这就是相当于SIMD

第二,不同的SM之间不能cooperate。而且local memory不能share,share的level是global
memory,需要手工定义,根本就不是uniform shared memory。不过这点不是很确定。很早以前看得paper了。

当然你对SM的调度可以手工指定的,但这就不是shared memory的编程模式,和传统的thread概念就不一样了。

最后,我个人认为,CUDA就是对GPU的一种hack而已。就以前和别人交流的情况看,学术界没有听说把CUDA称为多线程平台的。你要这样认为也可以,但把CUDA作为多线程并行平台的例子,我个人认为不合适。

To jiang li:

对,也就是在cluster上搞虚拟内存地址。

另外wiki上对于cluster的概念定义太狭窄,一堆computer可以搞cluster,一堆CPU也可以以node的概念搞cluster,Bluegene一出来的paper就是发表在ICCC上面的

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/2 qiaojie <qia...@gmail.com>:

jiang li

unread,
Mar 3, 2009, 12:49:50 AM3/3/09
to pon...@googlegroups.com
多谢指点。
不过关于cluster的定义,我想再请教一下。根据我的知识,cluster应该就是指一堆机器通过LAN的方式组合到一起。你所说的一堆CPU的cluster是不是应该叫multiprocessor system。关于这些概念的区分我不太确定,能不能给详细解释一下:)

2009/3/3 windstorm <likunar...@gmail.com>

windstorm

unread,
Mar 3, 2009, 1:12:45 AM3/3/09
to pon...@googlegroups.com
实际上你的理解不能说是错的。

我说的cluster就是一堆multiprocessor的组合,例如bluegene。只不过此时cluster的节点,通常偏向于CPU加内存,通过SAN链接起来的。当然人们也可以argue
CPU+内存就是computer了。所以这种概念很模糊。

而且“一堆机器通过LAN的方式组合到一起”肯定是不完善的概念,你可以看看这篇文章

http://ceng.usc.edu/smart/presentations/archives/AppendixE.ppt

我忘了以前看到概念的出处,貌似是Computer Architecture: A Quantitative Approach这本书的附录的介绍。

jiang li

unread,
Mar 3, 2009, 1:37:39 AM3/3/09
to pon...@googlegroups.com
谢谢。
难得碰上你这么一位专家,我多问几句。
bluegene这样的系统应该就是我们常说的超级计算机了。我感兴趣的是这样的系统它的软件架构是怎样的,是像google cluster那样在OS层上再搭建一个分布式的platform来调度各项资源,还是其它的方式,比如CPU的指令都是特别设计的,使之能够考虑到分布式系统的问题。我不太了解这方面的知识,描述有问题别介意啊。
如果能给些入门的资料或者论文就更好了:)

2009/3/3 windstorm <likunar...@gmail.com>

qiaojie

unread,
Mar 3, 2009, 1:32:58 AM3/3/09
to pon...@googlegroups.com
我认为你应该认真读一下CUDA的技术手册,不要在同一个概念的不同表述上做无意义的争论。你想表达的是CDUA的线程相比传统的CPU上的线程有很多限制,但是这些限制并不破坏做为线程这个概念的完备性。正如The Problem with Threads一文所论述的,不加限制的使用线程只能得到不确定的程序行为并且难以编程,因此未来的多线程模型也必然会存在分层次的内存访问限制,在类似像CUDA这样的框架上发展。



2009/3/3 windstorm <likunar...@gmail.com>

windstorm

unread,
Mar 3, 2009, 2:09:17 AM3/3/09
to pon...@googlegroups.com
Overview of the Blue Gene/L system architecture

我不确定你能不能找到,IEEE上好像都是abstract。如果找不到原文给我说声,我传给你。

windstorm

unread,
Mar 3, 2009, 2:33:25 AM3/3/09
to pon...@googlegroups.com
是谁告诉你“未来的多线程模型也必然会存在分层次的内存访问限制,在类似像CUDA这样的框架上发展”的?这个帽子除了Nvidia的人没人敢安吧?Thread不一定是未来多核的发展方向,CUDA肯定不是发展方向,现在一点也没有看出这种趋势的兆头。

唉,CUDA这么深入人心,就是Nvidia在CUDA推出的时候,到处去世界各地演讲忽悠来的。当时各个大学都开始尝试用CUDA编程,然后炒火了。

你既然已经承认thread会有不确定性,假设thread带来的不确定性加上分层内存带来的限制,会导致多核编程一点都不scalable。而且我觉得CUDA就是SIMD的模型,没有人会当作并行多线程模型来研究它,至少我没见过。

就算退一万步说,线程会是发展方向,也不会是CUDA这种非标准线程模型,而是类似于Larrabee的这种模型。你去看看Larrabee的架构,哪个才叫“并行多线程”?

顺便加一句,Thread继续发展的最大道理也就是legacy code很多。

你要真觉得CUDA就是好,那就坚持吧,这种就是个人选择而已。但是你把CUDA当作promising的并行多线程平台......

Anyway,我没什么多说的

qiaojie

unread,
Mar 3, 2009, 4:12:04 AM3/3/09
to pon...@googlegroups.com
说CUDA是忽悠.....你可以的
虽然你的口气确实是很大,但是我可以确信你基本上没怎么写过并行计算相关的程序,所以你并不理解分层次的内存存储模型对于并行程序的重要性。在现有内存模型基础上,CPU的双核4核一旦到了8核16核就发展不下去了,因为内存会成为严重的瓶颈。在未来Global/Constant/Local Memory的概念在并行计算模型里是不可或缺的。
如果你对“未来的多线程模型也必然会存在分层次的内存访问限制,在类似像CUDA这样的框架上发展”这句话有疑问,那我建议你去读一下OpenCL标准,OpenCL的分层次存储模型跟CUDA基本上是一致的,这份标准是有intel ,amd,nvidia,apple等几乎所有的软件硬件业巨头们共同制定的,如果你认为他们也是在忽悠你的话,那我除了问一句你妈贵姓之外实现想不出说什么了。




2009/3/3 windstorm <likunar...@gmail.com>

qiaojie

unread,
Mar 3, 2009, 8:00:53 AM3/3/09
to pon...@googlegroups.com
另外如果你对GPU不屑一顾的话,那么可以看看代表下一代并行计算架构的处理器CELL。CELL的架构有点类似于整合了CPU和GPU的架构,其每一个SPE具有自己的256K Local Memory,SPE要访问主内存的话同样受限并且速度较慢。
最近再给你科普一下为什么我们需要Local Memory。一直以来内存访问的速度都跟不上CPU的速度,到了多核时代这个问题显得更加严重。第一个问题是内存访问是串行化的,本来内存访问的带宽就不够了,被几个核心一瓜分,更显捉襟见肘,如果有每个核心可并行访问的内存,那么带宽一下就提高了N倍。第二个问题是核心跟内存之间有cache,如果某段内存在几个核之间读写共享,那么一旦内存值被某个核心修改了,为了保证一致性,其他核心的cache也要同步修改,这个同步的代价很大,所以最好的方案是让核心在专属于自己的Local Memory上完成大部分工作,这样每个核可以独立工作而不需要再同步状态了,只有真正需要在多个线程之间共享状态的时候再去访问主内存。至于为什么又要分Golbal Memory和ConstantMemory呢?这个问题留给大家回家思考了。


 
2009/3/3 windstorm <likunar...@gmail.com>

Linker

unread,
Mar 3, 2009, 8:10:05 AM3/3/09
to pon...@googlegroups.com
貌似CELL在设计上并不是很成功。
首先,CELL的设计复杂度太高。对于低成本生产是个挑战。
第二,CELL企图整合哈佛和冯诺依曼体系。这似乎并不是个好点子。
附一个参考连接
Intel也曾今在网络处理器这种类似架构的东西上做过失败的尝试。

不是,现在似乎随着技术的发展,情况有些变化。

OpenCL这东西估计还是比较靠谱的。比较看好。


2009/3/3 qiaojie <qia...@gmail.com>



--
Regards,
Linker Lin
linker...@gmail.com

qiaojie

unread,
Mar 3, 2009, 9:01:28 AM3/3/09
to pon...@googlegroups.com
不成功可能是因为我们在单核架构上的路径依赖造成的,不一定是技术上的问题,不能简单下定论。
当然最好是不要去随便置疑处理器的设计,一款CPU的诞生,意味着几十亿$的研发投入,无数的人年,以及如神一般的设计师.....设计者们必然经过非常小心谨慎的设计和取舍,不是我们这种外行可以随便置疑的。


 
2009/3/3 Linker <linker...@gmail.com>

windstorm

unread,
Mar 3, 2009, 12:55:30 PM3/3/09
to pon...@googlegroups.com
我承认CUDA是一个很好SIMD的平台,所以在大规模图形图像或者数据并行处理方面有很大优势,这就是为什么我说CUDA就是GPU的一个hack而已。我说整个CUDA忽悠是有点过了,但至少CUDA的线程模型是忽悠,你想看什么是不忽悠,不是给你推荐了Larrabee么。

包括你说的OPENCL,实际上这个是apple提出来,接受这个OPENCL的组织也是multimedia的组织而已,也就是说,如果你认为以后的多核编程全是图像处理,数据并行,那说不定CUDA这种编程模型还是有用的。

但显然,这并不是实际情况,举个最简单的例子,一个http server,怎么用CUDA handle呢?

既然你举了Cell的例子,Cell的推出是为了sony的ps3,相对于wii和xbox360来讲,Cell投资最多,但出货量最少,所以不是说投钱最多的东西就是好东西。应该说,我个人理解,就是因为Cell这种复杂编程模型给application的开发带来很大的困难,换句话来说,一个公司想开发cell上的程序,必须高价雇佣像你这样喜欢并行复杂编程模型的程序员。

你讲的关于cache coherence的问题,除了用你所说的用local memory的办法来解决,还有诸如像transactional
memory的办法解决,而你所谓的这种“local memory”的办法,只能是一种临时的解决方案,因为会带来很高的编程复杂度。

如果你就是一个programmer的话,你现在没什么办法,只能适应别人的架构和模型,但是小心哦,过了N年之后公司可能把你fire掉,因为这种编程的架构,因为编程的人太少,会逐渐消失的。

大家都是外行,但你不能接触内行,不代表别人不能接触内行。工业界的人通常都有大量编程经验,so
what?建议你多看看学术界的动向比较好,体系结构方面ISCA和HPCA还是每年都开得,看看有几个人还在“多线程复杂并行平台”的问题上纠缠。你有时间问“你妈贵姓”,不如给那些TPC发mail探讨一些这些问题,我保证你会有新的思路和见解的,那帮TPC有不少就是你所谓的“神一般的人物”。

Anyway,我不想在这个问题上和你继续纠缠,除非你有新的idea。

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/3 qiaojie <qia...@gmail.com>:

avalon

unread,
Mar 3, 2009, 2:07:22 PM3/3/09
to pon...@googlegroups.com
CUDA,ps3,都是很好的东西,其实如果了解nvidia在图形学发展的地位,就能明白
CUDA的意义,
当renderman的shader可以硬件化后,人们拿它还能做些什么呢?于是CUDA就自然
的登场了。
GPU还不存在什么thread模型,它没有thread context这个概念,也没有中断可
用,也无法切换,
事实上,也没必要抱着thread不放,我们这样来做并行计算,就是通过算法切割实
际问题,
分解计算到一些基本的原子向量计算,然后动态或静态的生成代码,在GPU或者CPU
控制下利用
并行单元来执行.至于目前CUDA能做哪些工作,这取决于算法的设计,能否做web
server,在以后,
也许可能,谁知道呢.

至于PS3的编程复杂性,感觉那纯属于软件设计的问题,如果没有CUDA,没有CG,
opengl和diretx,
直接面对GPU,恐怕GPU编程要比PS3还要麻烦...好在driver都替你做了。

其实CUDA的给我们的好处在于,你花上1W美金就可以搞到一台个人的超级计算机,
剩下的就发挥想象吧。。。

windstorm 写道:

windstorm

unread,
Mar 3, 2009, 2:27:33 PM3/3/09
to pon...@googlegroups.com
其实你说的和我说的没有什么矛盾

我一开始的立意就是(33楼)

1 多线程和“多核”没有“相互促进”的关系(和一些人讨论的见解而已,不认同的人可以不认同)

2 CUDA个人理解是一个很大的SIMD,不是线程的概念(这个争议应该不大吧?)

所以我赞同你的话。唯一需要提到的是,

“其实CUDA的给我们的好处在于,你花上1W美金就可以搞到一台个人的超级计算机, 剩下的就发挥想象吧。。。”

当然是大家都可以想象的,就是编程起来太难了。

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/3 avalon <aval...@gmail.com>:

qiaojie

unread,
Mar 3, 2009, 11:09:44 PM3/3/09
to pon...@googlegroups.com
我承认CUDA是一个很好SIMD的平台,所以在大规模图形图像或者数据并行处理方面有很大优势,这就是为什么我说CUDA就是GPU的一个hack而已。我说整个CUDA忽悠是有点过了,但至少CUDA的线程模型是忽悠,你想看什么是不忽悠,不是给你推荐了Larrabee么。

包括你说的OPENCL,实际上这个是apple提出来,接受这个OPENCL的组织也是multimedia的组织而已,也就是说,如果你认为以后的多核编程全是图像处理,数据并行,那说不定CUDA这种编程模型还是有用的。

你这种”白马非马“的狡辩就不要再拿出来献丑了,我前面已经说的够清楚了,CUDA架构跟SIMD是有本质区别的,CUDA的线程具备了线程的完整特性,对此有疑问的同学可以阅读CUDA手册,引用如下:
To manage hundreds of threads running several different programs, the
multiprocessor employs a new architecture we call SIMT (single-instruction,
multiple-thread)
......
SIMT architecture is akin to SIMD (Single Instruction, Multiple Data) vector
organizations in that a single instruction controls multiple processing elements. A
key difference is that SIMD vector organizations expose the SIMD width to the
software, whereas SIMT instructions specify the execution and branching behavior
of a single thread. In contrast with SIMD vector machines, SIMT enables
programmers to write thread-level parallel code for independent, scalar threads, as
well as data-parallel code for coordinated threads.
For the purposes of correctness,
the programmer can essentially ignore the SIMT behavior;

你还好意思拿尚未发布的Larrabee出来尽情yy,我也真是服了你了。等到Larrabee真的出来的时候,他的API可能就是OpenCL了,不要忘记Intel也是OpenCL的成员,没有理由让Intel另起炉灶开发出一个新的API,现在在CUDA上开发的程序将来可以很容易的迁移到OpenCL平台上,因为CUDA本来就是OpenCL的一个实现层。
 
 

但显然,这并不是实际情况,举个最简单的例子,一个http server,怎么用CUDA handle呢?

你举的这个例子显出你对并行计算的认知非常的肤浅。普通的http server的瓶颈是网络和磁盘I/O瓶颈,而不是CPU的计算资源不够,这个跟并行计算是两码事。但是如果你的http服务需要大规模的复杂计算,比如实时编码视频音频什么的,那么用CUDA显然可以解决问题。
 

既然你举了Cell的例子,Cell的推出是为了sony的ps3,相对于wii和xbox360来讲,Cell投资最多,但出货量最少,所以不是说投钱最多的东西就是好东西。应该说,我个人理解,就是因为Cell这种复杂编程模型给application的开发带来很大的困难,换句话来说,一个公司想开发cell上的程序,必须高价雇佣像你这样喜欢并行复杂编程模型的程序员。

你讲的关于cache coherence的问题,除了用你所说的用local memory的办法来解决,还有诸如像transactional
memory的办法解决,而你所谓的这种“local memory”的办法,只能是一种临时的解决方案,因为会带来很高的编程复杂度。

如果你就是一个programmer的话,你现在没什么办法,只能适应别人的架构和模型,但是小心哦,过了N年之后公司可能把你fire掉,因为这种编程的架构,因为编程的人太少,会逐渐消失的。

没有人会认为并行计算是一件简单的事情,技术大牛们都承认免费午餐的时代已经过去,接下来程序员必须面对现实,接受来自并行计算的复杂性。但是我看你除了抱怨并行编程太难并且束手无策,然后yy会有更好的技术出来拯救你,你还能提出什么建设性的意见来呢?如果你是programmer的话,我想老板fire的应该是你这种人才对吧?当然,我不否认未来可能会有更好的编程模型出现,但是在这样的编程模型尚未实用化之前,你最好学会接受现实。

Local Memory会带来很高的编程复杂度,更是你个人的yy而已。Local Memory其实是非常自然的解决方案,如果是多进程结构的话,每个进程都是Local Memory的,好像这篇帖子的初衷是想说明多进程优于多线程吧,so 用你的”Local Memory会带来很高的编程复杂度“去批判他们吧,我没意见。至于你说的transactional memory解决不了带宽问题。

  
大家都是外行,但你不能接触内行,不代表别人不能接触内行。工业界的人通常都有大量编程经验,so
what?建议你多看看学术界的动向比较好,体系结构方面ISCA和HPCA还是每年都开得,看看有几个人还在“多线程复杂并行平台”的问题上纠缠。你有时间问“你妈贵姓”,不如给那些TPC发mail探讨一些这些问题,我保证你会有新的思路和见解的,那帮TPC有不少就是你所谓的“神一般的人物”。

学术界自然可以天马行空般的提出各种可能性,但是工业界的话更关注的是可行性。举个例子吧:图形学里有个非常基础的算法是关于如何快速消除隐藏面的,20多年有人写篇paper总结了学术界提出的大约13种方法,最后一种算法是zbuffer  ——当时被作者认为是最不靠谱性能最差的算法最终成了工业界的标准算法,只是因为zbuffer最具备硬件加速的可行性。所以不要以为学术界没人谈多线程并行,多线程就会过时,工业界的选择才是未来的方向。事实上是以CUDA/OpenCL为代表的计算平台,已经指明了这个方向。





windstorm

unread,
Mar 4, 2009, 12:01:59 AM3/4/09
to pon...@googlegroups.com
鉴于你有新的论点,再给你多说两句

1 whereas SIMT instructions specify the execution and branching behavior


of a single thread. In contrast with SIMD vector machines, SIMT enables
programmers to write thread-level parallel code for independent,
scalar threads, as
well as data-parallel code for coordinated threads.

这不就是证明了我说的么。你当然可以specify the execution and branching behavior
of a single thread.

问题在于CUDA是怎么执行它的?然后我告诉你,

“如果线程处于不同的分支和跳转,他们会相互等待,对于大规模的数据并行这不是大问题,这也是为什么我认为它是一个SIMD的模型体现。但是对于细粒度的并行,比如instruction
level or task level的并行,CUDA就很难高效handle”

你给我argue

“同一时间里会有很多个wrap同时运行,而wrap之间的执行是独立的,不存在互相等待的问题”

我告诉你

“同一个SM只能执行一个wrap,在一个时间段内。这就是相当于SIMD

不同的SM之间不能cooperate。而且local memory不能share,share的level是global
memory,需要手工定义,根本就不是uniform shared memory。当然你对SM的调度可以手工指定的,但这就不是shared
memory的编程模式,和传统的thread概念就不一样了。”

这就叫线程不完备性,明白?

2 没有理由让Intel另起炉灶开发出一个新的API?你比我还要行,我只是批判一下CUDA而已,你连人家Intel的蓝图都规划了

看看这个吧

http://techresearch.intel.com/articles/Tera-Scale/1514.htm

3 http server确实不恰当,总的来说就是这种细粒度的每个thread做不同的branch的任务。你要真觉得CUDA好handle,OK,go on。

4 Local Memory会带来很高的编程复杂度不是我的yy,唉。也没听说过“Local
Memory其实是非常自然的解决方案”,我觉得是你自己的yy吧,我告诉你Local
Memory的问题是难以调度,特别要求程序员对底层硬件工作原理特别了解,这造成了人力成本急剧上升。如果你调度不好Local
Memory,说不好听的,就等死吧。

5 事实上是以CUDA/OpenCL为代表的计算平台,只是流处理的某种代表。流处理语言海了去了,Brook/+,CT,streamc,etc。CUDA只是宣传最为猛烈的而已。而且也就你把CUDA当作“多线程并行”计算平台的发展方向。

6 我暂时还不会混工业界,不用你担心我被fire。只是我实在想不出你迷信CUDA是“并行计算平台发展方向”的理由,也许你现在就是CUDA
programmer,也许还是高水平的,特佩服CUDA。但你这个“发展方向”实在有点信口开河。将来并行平台可能是application
specific的,也可能是有新的平台出来一统天下,但这个平台绝对不会是CUDA,而在流处理领域,没几个学术界大牛看好CUDA的。说了半天你还是没看Larrabee的架构吧?光这个架构看好程度就比CUDA大。

7 你要继续你的CUDA,没问题,个人选择而已,但别扣什么“平台发展方向”的帽子了。唱衰多线程并行平台的paper,你想要我可以给你找一箩筐。Edward
A. Lee的paper给你看了,你说人家空谈,他在体系领域的地位至少都是和你口中那些“神人”一个级别的。将来可能的并行平台模型,他也提出来了,不过不是这篇paper而已,你自己去看看他的主页

http://ptolemy.eecs.berkeley.edu/~eal/

8 如果你还想继续这种“发展方向”的争论,恕不奉陪。反正Post也摆在这里,希望得到信息的人自然会从中提取。

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/3 qiaojie <qia...@gmail.com>:

windstorm

unread,
Mar 4, 2009, 12:09:57 AM3/4/09
to pon...@googlegroups.com
关于CUDA我补充一句,免得别人误解

对于CUDA线程,我的意见:

1 CUDA有没有线程? 有
2 CUDA是不是线程完备? 不是
3 CUDA这种手工指定的调度适合不适合细粒度大规模branch任务? 我认为不适合。别人可以自行判断。

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/3 windstorm <likunar...@gmail.com>:

uan

windstorm

unread,
Mar 4, 2009, 12:36:05 AM3/4/09
to pon...@googlegroups.com
我明白为什么你不理解“Local Memory会带来很高的编程复杂度”了

如果我没有估计错,你应该就是GPGPU的programmer吧。

那就正常了,因为你所处理的数据就根本不用担心复杂调度的问题。Local memory这种设计就是CUDA这种应用数据的specific
design。你也没有接触过这种细粒度多branch的并行任务。

我给你举个例子,你就知道为什么CUDA不会是发展方向。你去看看Sun的Rock和Niagara
1/2,注意看架构的区别,你就知道为什么说CUDA是data specific design。你也就会明白为什么我说

“将来并行平台可能是application specific的,也可能是有新的平台出来一统天下,但这个平台绝对不会是CUDA”

http://en.wikipedia.org/wiki/UltraSPARC_T2
http://en.wikipedia.org/wiki/Rock_processor

相关paper可以在wiki的reference中找到

还有,Niagara和Larrabee的线程才叫完备性,这就是他们和CUDA能做的事情的区别之一。

对于Larrabee,我估计你到死也不愿意去看他的设计吧。你看了就知道为什么Intel不会在上面用OPENCL了。

http://www.spectrum.ieee.org/jan09/7129

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

o

qiaojie

unread,
Mar 4, 2009, 1:21:00 AM3/4/09
to pon...@googlegroups.com
如果你一定要认为具备系统线程的全部特性才能叫线程的话,那你就这么认为好了,这个问题各自持保留意见
好了。

但是你一方面拿Larrabee出来证明CUDA的线程不完备,说Larrabee才是真正的多线程并行计算,一方面又大
谈多线程并行计算不是并行计算的主流方向,我不知道你到底想证明什么?照你这么说,既然多线程已经过时
了,那么CUDA是垃圾,Larrabee也是垃圾咯?

还是说点有用的话题吧,我承认CUDA是专为data level而不是task level设计的并行计算平台,所以CUDA对你所
一直热衷的基于task level的并行计算无效,而你一直强调的那些多线程编程困难性在data level上并不存在,所以
CUDA至少可以成为并行计算的一个分支上的主流方向。事实上我们确实有很多data level的大规模计算问题需要
解决,多媒体只是一个方面,在科学计算领域(例如大规模搜索,非线性系统模拟等等)也基本上都是这类问题,
过去设计制造的超级计算机也都是用来解决这类问题的。

至于你说的task level的并行计算,目前据我所知并没有很好的解决方案,编程的复杂性大多源于此,说不定这根
本就是一个无解的问题呢?至少目前一个可能的折衷方案就是把task level的问题分解为一个个小的data level的问题
来解决,貌似是cell倡导的解决方案。实在解决不了,我们也可以先不解决这些问题,也没有人逼你一定非要把难以
并行化的问题并行计算吧?





2009/3/4 windstorm <likunar...@gmail.com>

windstorm

unread,
Mar 4, 2009, 2:00:04 AM3/4/09
to pon...@googlegroups.com
我提Larrabee的原因,就是因为Larrabee更加像是一个统一的方案。

我一开始就谈到了,并行平台发展,要不然你用全新的概念,比如actor这种,要不然你用现有的架构,但是specific
application。而CUDA的问题是过于specific application了,但是像Larrabee这种线程完全完备的,task
level也能处理很好。

Larrabee虽然没有正式推出,但是其优点在学术界早就开始探讨了,很多人就是拿CUDA作为反例。CUDA,以及其所采用的local
memory机制,一旦跳出这个领域,相较于其变成复杂性,真的就是一个死。Larrabee允许现有程序员不经过任何特殊training就上手编程,包括图形图像,科学计算,或者网络处理,各个领域。cell和CUDA谁能做到?

你可能觉得没什么,但是如果Larrabee真的和其资料显示的那样,至少在GPGPU方面,公司的倾向性会非常明显。你去哪里找那么多对底层和开发都精通的程序员?

Anyway,CUDA现在当然是有用的,我们这里用CUDA的lab也是一堆。只是在探讨“未来的发展趋势”的时候,我只能说,我自己,包括以前交流的人,没有把CUDA作为方向的。

其实说这些趋势都是虚的,让时间说话吧。

jiang li

unread,
Mar 4, 2009, 2:14:15 AM3/4/09
to pon...@googlegroups.com
虽然我不喜欢在网上争吵,不过二位的辩论都迫使对方贡献出了很多有价值的信息,我受益匪浅啊:)

关于“多线程不是并行计算的主流”这个话题,我刚看了在Edward A. Lee的主页上找到的一段presentationhttp://ptolemy.eecs.berkeley.edu/~eal/videos/EALatMSR_Jan07/default.htm
作者对于多线程的意见在于,如果你的并行计算是需要任务之间有很多交互的话,会产生很多意想不到的状况。那么在多线程+互斥锁的条件下,即便是很有经验的程序员也难保证写出没有bug的程序。作者举了一个很典型的例子说明这个问题,一段2000年的多线程程序在2004年的时候突然出现了一次deadlock,而且还是在很重要的场合(详见视频)。
我想是不是因为如此,所以erlang里面的处理单元(所谓进程)也是采用消息传递的机制而不是内存共享的机制。
windstorm,不知道我理解得对不对?


2009/3/4 qiaojie <qia...@gmail.com>

windstorm

unread,
Mar 4, 2009, 2:32:06 AM3/4/09
to pon...@googlegroups.com
是这样的,我对erlang不是很了解,但是对于并行编程来说,最本质的问题就是它会出现共享的情况。这是任何编程语言都无法避免的,所以你的trick就在于,怎么去处理这种共享的情况。

一种就是显示控制,比如erlang这种消息机制,一种就是隐式控制,比如共享内存。

那么,两者有什么区别呢?对于显式控制的语言,它的缺点在于编起来比较麻烦,好处在于性能会比较好。对于隐式控制的语言则刚好相反,你根本不用去care这些东西,但性能就会有牺牲。

这是productivity和efficiency的trade off。

至于Lee谈到的Bug问题,我个人理解和消息机制或者共享内存没啥关系,这是多线程并行计算故有的问题,你用erlang也可能遇到这种情况。

再深入的我就没法解释了,因为我对erlang本身不是很了解。但如果你还有更深入的问题,可以提出来,TP说不定有了解的,实在不行我可以拿来问问我朋友的老板,他是编程语言界大牛。

我其实对这个话题很感兴趣的,可惜一直没时间去看。

----------------------------------------------------------------------------------
Yours Sincerely
Kun

blog: www.forwind.cn

2009/3/4 jiang li <li.ji...@gmail.com>:

qiaojie

unread,
Mar 4, 2009, 2:54:57 AM3/4/09
to pon...@googlegroups.com
从Larrabee已公开的资料看,Larrabee似乎是解决了多核之间cache coherency的问题,并且多核之间共享内存也不存在带宽问题,数据居然可以以光速穿越多个核并保证其一致性,这确实是件让人匪夷所思的事情,如果真能如期发布那是个了不起的突破。不过貌似也有提到 Larrabee includes explicit cache control instructions to reduce cache thrashing.  看样子要做到完全透明不需要程序员考虑底层机制也不太现实吧。而且我依然对Larrabee所能达到的内存带宽持怀疑态度。


2009/3/4 windstorm <likunar...@gmail.com>

qiaojie

unread,
Mar 4, 2009, 3:26:34 AM3/4/09
to pon...@googlegroups.com
erlang的话并不是什么新鲜概念,他的设计思想源自于Functional Programming,本质上就是一个支持异步通讯机制的Lisp,erlang的消息传递跟无副作用(no side effect)的函数调用是等价的。no side effect是限制对共享状态修改的约束条件。一旦你能把问题分解为no side effect的函数,那么并行化执行他们就变成非常自然的事情,而不再需要考虑锁的问题。erlang特别适合于构造那种基于流水线的并行计算模型,不过这里存在许多难题,第一个是消息传递有overhead,如果你的某一级流水线的处理时间小于这个overhead的话,那么并行化不可能获得性能正收益,这个限制了并行化的粒度。第二个问题是把问题分割成流水线不是件容易的事情,各个流水线级之间的负载不可能均衡,所以很容易在某级流水线上出现性能瓶颈,而要优化这些瓶颈就比较困难了。第三个问题是流水线级别越长任务传递的延迟就越长,如果问题对延迟很敏感,那么就算流水线能满足吞吐量,也无法保证实时性。

不管怎么说,并行计算都不是件容易的事情,有针对某类问题的特定解决方案,但是要找到一个全面的方案解决所有的问题目前是不现实的。


2009/3/4 jiang li <li.ji...@gmail.com>

Rockins Chen

unread,
Mar 4, 2009, 7:58:00 AM3/4/09
to pon...@googlegroups.com
不同意你这种讨论问题的方式。

我同意windstorm的两点看法:
1、thread不会是未来有希望的计算模式
2、thread目前的繁荣是为了支持legacy code

-rockins

2009/3/3 qiaojie <qia...@gmail.com>



--
BRs,
Rockins Chen
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UESTC, Chengdu, Sichuan, China
http://rockins.cn/
ybc...@gmail.com

Rockins Chen

unread,
Mar 4, 2009, 8:00:35 AM3/4/09
to pon...@googlegroups.com
补一句,我说的不同意是不同意你在讨论中问候别人母亲的贵姓。这个世界贵在求同存异,你可以喜欢你喜欢的,但是也应该允许别人有不同意见。技术看法上的分歧不应该用骂街的方式处理。

-rockins

2009/3/4 Rockins Chen <ybc...@gmail.com>

Rockins Chen

unread,
Mar 4, 2009, 8:29:22 AM3/4/09
to pon...@googlegroups.com


2009/3/4 windstorm <likunar...@gmail.com>
是这样的,我对erlang不是很了解,但是对于并行编程来说,最本质的问题就是它会出现共享的情况。这是任何编程语言都无法避免的,所以你的trick就在于,怎么去处理这种共享的情况。

一种就是显示控制,比如erlang这种消息机制,一种就是隐式控制,比如共享内存。
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

这里是不是说反了,我觉得共享内存是显式控制,消息传递才是隐式控制涅。
 

windstorm

unread,
Mar 4, 2009, 4:05:50 PM3/4/09
to pon...@googlegroups.com
我说的控制不是锁机制,而是具体“怎么同步”这个概念是显示还是隐式的

当然,显式还是隐式没有一个标准说法,我的理解是错的也是可能的。不要过于当真:)

----------------------------------------------------------------------------------
Yours Sincerely
Kun

2009/3/4 Rockins Chen <ybc...@gmail.com>:

qiaojie

unread,
Mar 4, 2009, 9:37:58 PM3/4/09
to pon...@googlegroups.com
哟,被人揪着小辫子了,不过貌似我用的是“如果....,,那么....”句式,虚拟语气么,调侃都不懂,真是无趣的人。


 
2009/3/4 Rockins Chen <ybc...@gmail.com>
Message has been deleted

Rockins Chen

unread,
Mar 5, 2009, 12:29:37 AM3/5/09
to pon...@googlegroups.com
如果是这样,那的确是误会。

2009/3/5 Hook <hook.hu@gmail.com>

“你妈贵姓”出自周星驰《大话西游》,用来表示提起一个很无聊很没有意义的话题。并非骂人。Rockins Chen大约是误会了

 

发件人: pon...@googlegroups.com [mailto:pon...@googlegroups.com] 代表 qiaojie
发送时间: 星期四 20090305日 上午 10:38
收件人: pon...@googlegroups.com
主题: [TopLanguage] Re: 进程还是线程?这是个问题! by 编程随想

Linker

unread,
Mar 5, 2009, 4:48:53 AM3/5/09
to pon...@googlegroups.com
同意qiaojie的大部分观点. 
我也认为OpenCL是很有前途的方向. 
但是上一次听CUDA的讲座, 了解到GPU里面目前最大的缺陷是指令缓存(ICache)很小.
这点对于复杂的业务逻辑, 尤其是分支较多的逻辑不是很有效. 
这个缺点,也是所有哈佛架构处理的缺点.
DSP, Network Processor , GPGPU 都是哈佛架构.
在这个架构里, 指令和数据是分离的.
可写存储器是没有透明读写CACHE的.
只读存储器有只读CACHE.
这样的架构, 目前还没有合适的FP语言与之相匹配.
也许,需要有种Erlang的哈佛特化版本?



2009/3/5 qiaojie <qia...@gmail.com>

qiaojie

unread,
Mar 5, 2009, 9:27:05 AM3/5/09
to pon...@googlegroups.com
我觉得问题到不是哈佛架构还是冯氏架构,这两种架构对软件层的影响不是很大。
FP类的语言虽然在软件上很完美,而且天生具有并行执行的能力,但在性能上却
一直没法跟命令式语言比,特别是no side effect的约束条件是非常强的约束,连变
量赋值这样的操作都是不允许的,而具有side effect的函数都必须串行化执行,这样
本身会造成编程困难,在性能上也是需要置疑的。并行计算本身就是为了解决性能
问题而出现的,如果语言本身有性能问题,那很可能会得不偿失。所以,我认为像
erlang这样的语言可能未必是将来并行计算的主流方向,erlang更像是分布式时代的
产物。

 
2009/3/5 Linker <linker...@gmail.com>

up duan

unread,
Mar 5, 2009, 10:50:41 PM3/5/09
to pon...@googlegroups.com
隔离并通过消息实现通信【以及同步】跟通过共享内存实现通信说哪一个是显式哪一个是隐式其实依赖于立场的。
通过消息要想通信,必须明确的提出【也就是消息传递】,而通过共享内存实现通信,则直接可用。所以从这个角度来说,消息是显式,共享是隐式。
而从另一个角度来说,为了实现同步【通信可以是它的机制,也可以是依赖于它来实现】,通过消息则是隐式实现的,通过共享,则需要显示的控制同步。从这个角度来说,消息是隐式的,共享是显式的。

2009/3/5 qiaojie <qia...@gmail.com>

up duan

unread,
Mar 5, 2009, 10:55:08 PM3/5/09
to pon...@googlegroups.com


2009/3/5 qiaojie <qia...@gmail.com>

我觉得问题到不是哈佛架构还是冯氏架构,这两种架构对软件层的影响不是很大。
FP类的语言虽然在软件上很完美,而且天生具有并行执行的能力,但在性能上却
一直没法跟命令式语言比,特别是no side effect的约束条件是非常强的约束,连变
量赋值这样的操作都是不允许的,而具有side effect的函数都必须串行化执行,这样
本身会造成编程困难,在性能上也是需要置疑的。并行计算本身就是为了解决性能
问题而出现的,如果语言本身有性能问题,那很可能会得不偿失。所以,我认为像
erlang这样的语言可能未必是将来并行计算的主流方向,erlang更像是分布式时代的
产物。

窃以为你这段话不自洽。你首先说FP的性能低下,然后又说Side Effect强迫串行化,会造成性能低下。你觉得究竟是那个性能低下?

更重要的倒不在于现实中哪个性能低下,而是逻辑上哪个性能低下。因为如果是逻辑上限制了性能,那么就无可奈何了,而如果只是实现上的问题导致的性能低下,只要有需求,总是可以改进的。实例就是Java的性能改进曲线。

qiaojie

unread,
Mar 6, 2009, 1:20:03 AM3/6/09
to pon...@googlegroups.com
你误解了我的意思,我的意思是说FP语言本身不可能避免串行化,FP语言对有无side effect的函数做了严格的区分,将no side effect的函数并行化,而有side effect的函数都必须串行化执行,这样才能保证程序的正确性。但是其实有些具有side effect的函数是可以并行化的,如果过分严格的串行化,就可能导致性能问题。
语言的性能对于并行计算来说的话是非常重要的,因为各种因素使得性能跟执行核数之间不是线性关系,假设FP语言比命令式语言慢了10倍,不可能通过增加10倍的核数来弥补,可能需要多的多的核或者根本弥补不过来。那么这种并行算法就是完全失效的。
目前为止,我曾经参与过的一个最复杂的分布式并行系统是基于ICE的网络游戏服务器Wish,是ICE开发小组成员亲自开发的服务器系统(当年是作为ICE的主打产品来宣传的)。这个项目最终以失败告终,当然失败有很多其他的原因,这里具体不多说了。我只简单说说一下服务器的问题。Wish服务器的程序员本身在分布式领域有很多年的开发经验,应该说从代码的质量来看还是相当高的,但是事后看服务器的架构设计基本上是完全失败的。Wish里的每一个功能模块都是一个独立的服务,可以任意部署到一个进程或者多个进程里,从表面上看这个设计具有很高的伸缩性,(当时的wish小组是搞了88台服务器的集群),但是实际上通过我们做的一些简单的profile,就明显的发现很多服务的性能不能随着服务器的增加而显著提升,很多服务部署到一个进程里反而性能更好(因为减小了通讯成本)。而由分布式编程带来的复杂性则使得开发变得尤其的困难,很多困难是没有做过的人想不到的,比方说部署及维护上的繁杂,关闭重启一下服务器需要很长时间,跟踪调试彻底失效(因为很容易的,一个方法调用就跑到另外一个进程里去没法跟踪了),编程上更是受到诸多限制导致很多不必要的复杂性。事后我也进行过一些总结,首先就是并行计算,并行只是提高性能的手段而不是目的,在并行化之前要非常仔细的考察性能问题,否则很有可能得不偿失。




2009/3/6 up duan <fix...@gmail.com>

up duan

unread,
Mar 6, 2009, 2:22:55 AM3/6/09
to pon...@googlegroups.com
2009/3/6 qiaojie <qia...@gmail.com>

你误解了我的意思,我的意思是说FP语言本身不可能避免串行化,FP语言对有无side effect的函数做了严格的区分,将no side effect的函数并行化,而有side effect的函数都必须串行化执行,这样才能保证程序的正确性。但是其实有些具有side effect的函数是可以并行化的,如果过分严格的串行化,就可能导致性能问题。

哦,我想错了。不过PureFP是纯粹的NoSideEffect的。而所有的命令式语言都是严格的串行化的。 

语言的性能对于并行计算来说的话是非常重要的,因为各种因素使得性能跟执行核数之间不是线性关系,假设FP语言比命令式语言慢了10倍,不可能通过增加10倍的核数来弥补,可能需要多的多的核或者根本弥补不过来。那么这种并行算法就是完全失效的。

对。可是我的理解是即便现在FP比命令式语言慢10倍,也不是由于FP天生有什么缺陷导致的。而是FP编译器导致的。当然,FP的数学模型是递归函数,而命令式语言的数学模型是图灵机,虽然两者逻辑等价,但是针对冯诺依曼机器写程序无论是思路还是经验都是命令式语言的优势。或许两个模型转换在实现上还不是那么无关痛痒。
我认为硬件体系现在简单的增加Core来提高运算速度是绕道了。进一步的讨论可以看看 http://www.javaeye.com/topic/231515

目前为止,我曾经参与过的一个最复杂的分布式并行系统是基于ICE的网络游戏服务器Wish,是ICE开发小组成员亲自开发的服务器系统(当年是作为ICE的主打产品来宣传的)。这个项目最终以失败告终,当然失败有很多其他的原因,这里具体不多说了。我只简单说说一下服务器的问题。Wish服务器的程序员本身在分布式领域有很多年的开发经验,应该说从代码的质量来看还是相当高的,但是事后看服务器的架构设计基本上是完全失败的。Wish里的每一个功能模块都是一个独立的服务,可以任意部署到一个进程或者多个进程里,从表面上看这个设计具有很高的伸缩性,(当时的wish小组是搞了88台服务器的集群),但是实际上通过我们做的一些简单的profile,就明显的发现很多服务的性能不能随着服务器的增加而显著提升,很多服务部署到一个进程里反而性能更好(因为减小了通讯成本)。而由分布式编程带来的复杂性则使得开发变得尤其的困难,很多困难是没有做过的人想不到的,比方说部署及维护上的繁杂,关闭重启一下服务器需要很长时间,跟踪调试彻底失效(因为很容易的,一个方法调用就跑到另外一个进程里去没法跟踪了),编程上更是受到诸多限制导致很多不必要的复杂性。事后我也进行过一些总结,首先就是并行计算,并行只是提高性能的手段而不是目的,在并行化之前要非常仔细的考察性能问题,否则很有可能得不偿失。

哦,呵呵,原来Wish项目失败了呀。这是第一次听说。 我一直认为,一个基于RPC的【抱歉,很多人愿意说那是面向对象的,不是RPC的,不过我还是把它们分成一类】分布式体系,永远比一个基于数据copy的【REST之类的】体系缩放性差些。RPC的适合各个部分有复杂的互动。而Wish项目的强行分开以便于产生强互动的做法却有点搬石头上山的味道。
顺便说说题外话:我认为逻辑上紧密的东西物理上也应该紧密,否则不容易理解,性能低下,可扩展性也差。我的blog 有一个关于模块化的讨论就是这个方面。

qiaojie

unread,
Mar 6, 2009, 4:12:31 AM3/6/09
to pon...@googlegroups.com
你的文章有点意思。事实上GPU所以取得成功就是因为GPU是数据驱动的流处理器。我们不可能把程序全部转换为数据驱动
的,而CPU的乱序执行设计是自动一种自动把控制驱动转换成数据驱动的机制,但是数据显示不管CPU的设计师怎么努力,都
无法使得CPU一个时钟周期内同时平均执行超过2条指令,所以基本上自动转换的机制也是不能指望的。所能想到比较可行的方
案就是将CPU和流处理器整合起来,手工编程把需要并行计算的问题转化为数据驱动在流处理器上执行,事实上以CUDA为代
表的这类系统已经取得了很大的成功,这就是我看好CUDA的原因。不过貌似CUDA现在内部还缺乏构建流水线的基础设施
(而GPU是大量基于流水线的),这点是我不能确定的,是否未来我们需要这些基础设施来构建更复杂的并发应用。





2009/3/6 up duan <fix...@gmail.com>

sjinny

unread,
Mar 6, 2009, 8:03:43 AM3/6/09
to pon...@googlegroups.com
恩,以前学过一段时间ICE。
根据你的这句描述:“跟踪调试彻底失效(因为很容易的,一个方法调用就跑到另外一个进程里去没法跟踪了)”,我猜想你们把ICE的RPC真的当成了本地调用来用了……很可能是进程之间发生了过多的耦合,导致复杂度比单进程还要高。这应该就是RPC的典型问题,倒不是说RPC的形式有什么问题,而是它的意图容易导致进程之间的耦合过高、复杂度隔离不干净。
如果复杂度隔离得干净,那么一个进程应该只需要关注自己的任务,调试的时候也可以分开调试。其中消息的记录和回放也很重要。


网易邮箱,中国第一大电子邮件服务商

sjinny

unread,
Mar 6, 2009, 8:12:16 AM3/6/09
to pon...@googlegroups.com
这句非常认同:
本质上高耦合的东西在形式也应该高耦合,本质上低耦合的东西在形式上也应该低耦合。形式和内容应该一致。


在2009-03-06,"up duan" <fix...@gmail.com> 写道:
顺便说说题外话:我认为逻辑上紧密的东西物理上也应该紧密,否则不容易理解,性能低下,可扩展性也差。我的blog 有一个关于模块化的讨论就是这个方面。



网易邮箱,中国第一大电子邮件服务商

qiaojie

unread,
Mar 6, 2009, 10:05:52 AM3/6/09
to pon...@googlegroups.com
这个不是耦合性的问题,而是分布式对象不适用于频繁的细粒度交互。简单跟你说吧,在Wish里一个角色就是一个分布式对象,这个对象要跟其他分布式对象交互,而交互都是基于RPC的。因为通讯成本太高,所以这种设计基本是就是死路一条。

2009/3/6 sjinny <sji...@163.com>

sjinny

unread,
Mar 6, 2009, 3:23:10 PM3/6/09
to pon...@googlegroups.com
这就是耦合的问题了。如果把系统中的所有概念放在一个平面上,每个概念是一个点,点与点之间的距离表示耦合度,距离越远耦合越低,这时模块的边界应该处于最稀疏的地方,而你说的这种设计则会反过来……
并不是分布式对象本身有问题,而是把不合适的东西分在了网络两头。有些对象是可以分开的,有些则不适合。


网易邮箱,中国第一大电子邮件服务商

qiaojie

unread,
Mar 6, 2009, 9:47:44 PM3/6/09
to pon...@googlegroups.com
你这属于纸上谈兵。wish的设计目标就是不限数量的玩家在一个无缝世界里交互,说不限数量有些夸张,但88台服务器支持1w玩家还是可以的。把游戏里的角色设计成分布式对象是很自然的想法,那你觉得应该如何设计?

 
2009/3/7 sjinny <sji...@163.com>

sjinny

unread,
Mar 7, 2009, 12:06:24 AM3/7/09
to pon...@googlegroups.com
可以参考云风blog上的一些文章,我比较认同里面的做法。简单的说就是按照系统功能来进行任务划分:
比如空间管理任务,它负责对空间进行划分,并高效地进行空间查询和碰撞检测;
比如战斗任务,它负责战斗相关的逻辑判断和数据计算;
……
只要每个任务的责任(内涵)明确,接口(外延)简洁,那么剩下的事情主要就是如何在确保前面两点的前提下使得一个功能流程涉及的任务尽量少。
但是如果只是“把游戏里的角色设计成分布式对象”,我认为是无法确保前两点的,而前两点做不到那么这个系统一定会复杂到崩溃的。

网易邮箱,中国第一大电子邮件服务商

qiaojie

unread,
Mar 7, 2009, 1:17:59 AM3/7/09
to pon...@googlegroups.com
这个设计是你自己臆想出来的吧?有经过实际验证吗?空间任务管理角色移动/空间查询,战斗任务进行逻辑判断和数据计算,还有聊天任务,交易任务....OK,任务是分割到进程了,那么对象的状态在哪里?
还是来看个具体用例:玩家A向玩家B发起一个远距离的火球的攻击。流程大致为:服务器收到A的攻击指令,根据A和B的各属性检查攻击合法性,设置A状态为攻击准备状态(此时要禁止移动和其他动作),根据A的属性和装备计算伤害值,0.5秒后根据B当前位置发射火球,模拟火球运动,1秒后击中B,根据B的属性计算伤害及其他属性。
这是一段典型的战斗用例,涉及到角色位置、装备、角色属性等等多种共享状态,请你详细的描述一下你的战斗任务的处理流程,以及任务如何正确的存取这些共享状态。
 
另外,Wish的分布式对象设计虽然带来了很多的复杂性但还不至于让人崩溃,实际上系统已经开发完成,只是性能上并不如预计的那样有良好的伸缩性,很多情况下分布式反而得不偿失,这是我认为它失败的地方。
 
 

 
2009/3/7 sjinny <sji...@163.com>

sjinny

unread,
Mar 7, 2009, 7:11:48 AM3/7/09
to pon...@googlegroups.com
其实是云风的blog上描述的……当然也许我描述得并不精确。
对于火球法术来说可以这样:
1.A给服务器发命令要攻击B,接入进程根据配置表把相关的数据打包路由给战斗进程
2.战斗进程收到命令后,根据战斗逻辑进行预判,如果允许攻击,则记录下这个行为,并向位置进程发命令,要求创建一个火球的实体进行运动模拟,并订阅火球与其他实体发生碰撞的事件,并且可以说明这个火球一旦碰撞到特定类型的实体就会自动消失
3.位置进程会对火球和其他实体的运动进行模拟,并且会给其他客户端进行运动同步,当发生碰撞时就通知这个事件的订阅者(这里是战斗进程),并且会有超时的功能(或者说是实体有生命期)
4.战斗进程收到火球碰撞的事件或者超时事件,那么就会取出关于这个对象的战斗记录:火球法术。然后根据事件判断要做些什么,如果是要修改对象属性,那么就可以发消息给对象管理器去修改属性。属性修改可能只是一个值或者一个增量,也可能是一个公式id加参数。
对于共享状态,要么尽量减少它,要么就要有一定的通信手段,比如:
1.事件的订阅/发布机制
2.在产生请求时能够根据配置把对方所需的数据与命令一起发送过去
3.显式查询
4.可能还有其他办法
如果两个进程之间需要共享的东西太多,特别是需要实时共享的东西太多,那么说明两个进程耦合太大,需要从设计的层面进行考虑。
当然,这方面我也不是很在行,不过这是我学习的方向。
 
我*猜测*越复杂的东西伸缩性越难保证……只是猜测……
不过wish最终是因为性能不足导致部署成本太高,还是有其他商业上的原因?


网易邮箱,中国第一大电子邮件服务商

qiaojie

unread,
Mar 7, 2009, 10:30:33 AM3/7/09
to pon...@googlegroups.com
稍微来个具体的实例分析就能看出你的设计有多么的不靠谱
首先战斗计算的开销非常小,一般都是些简单的加减运算,几乎不耗什么CPU,反倒是把数据序列化通过网络传输再反序列化的开销要大很多,把战斗计算分离出来是典型的吃肥走瘦。而位置管理则是一个计算密集型服务,算法复杂度为m * n,如果角色多的话最容易出现瓶颈。你把不该并行的并行了,需要并行的却没有并行化。
需不需要并行计算以及怎么分割任务跟耦合度是没有关系的,很多时候就是要把某个高度内聚的模块分割开来并行计算,比方说碰撞检测和物理模拟是个计算密集型模块,现在有不少物理引擎已经可以做到并行化计算,甚至放到GPU里计算。


 
2009/3/7 sjinny <sji...@163.com>

sjinny

unread,
Mar 7, 2009, 11:14:06 AM3/7/09
to pon...@googlegroups.com
呵呵,我也只是刚开始学习这些,当然会不靠谱。
不过任务划分首先就不是按照性能需求来划分的……比如说战斗计算,也许它消耗不多,但是其中可能涉及各种易变的公式、规则,所以应该独立出来。至于位置管理,不知道你所说的m*n里的m和n分别是指什么,你所说的m*n的算法是什么算法。空间分割的算法很多,比如直接寻址的四叉树的话空间查找还是很快的,根据具体需要进行优化的话也有很多余地。
我觉得首先要关注的是任务分割以及复杂度隔离,而不是什么并行之类的。让一个正确的程序变快比让一个快速但设计错误的程序变正确要更容易,不过这话不是我说的……
你当然可以把碰撞检测和运动模拟分开:运动进程负责更新对象位置,碰撞进程负责碰撞检测,然后运动进程驱动碰撞进程,并向碰撞进程订阅碰撞事件。只不过前提是要做好分割,设计好交互协议。
在我看来,多进程设计是分割问题、控制复杂度的方法,而性能优化只是顺便的事情。

在2009-03-07,qiaojie <qia...@gmail.com> 写道:
稍微来个具体的实例分析就能看出你的设计有多么的不靠谱
首先战斗计算的开销非常小,一般都是些简单的加减运算,几乎不耗什么CPU,反倒是把数据序列化通过网络传输再反序列化的开销要大很多,把战斗计算分离出来是典型的吃肥走瘦。而位置管理则是一个计算密集型服务,算法复杂度为m * n,如果角色多的话最容易出现瓶颈。你把不该并行的并行了,需要并行的却没有并行化。
需不需要并行计算以及怎么分割任务跟耦合度是没有关系的,很多时候就是要把某个高度内聚的模块分割开来并行计算,比方说碰撞检测和物理模拟是个计算密集型模块,现在有不少物理引擎已经可以做到并行化计算,甚至放到GPU里计算。


 
2009/3/7 sjinny <sji...@163.com>
其实是云风的blog上描述的……当然也许我描述得并不精确。
对于火球法术来说可以这样:
1.A给服务器发命令要攻击B,接入进程根据配置表把相关的数据打包路由给战斗进程
2.战斗进程收到命令后,根据战斗逻辑进行预判,如果允许攻击,则记录下这个行为,并向位置进程发命令,要求创建一个火球的实体进行运动模拟,并订阅火球与其他实体发生碰撞的事件,并且可以说明这个火球一旦碰撞到特定类型的实体就会自动消失
3.位置进程会对火球和其他实体的运动进行模拟,并且会给其他客户端进行运动同步,当发生碰撞时就通知这个事件的订阅者(这里是战斗进程),并且会有超时的功能(或者说是实体有生命期)
4.战斗进程收到火球碰撞的事件或者超时事件,那么就会取出关于这个对象的战斗记录:火球法术。然后根据事件判断要做些什么,如果是要修改对象属性,那么就可以发消息给对象管理器去修改属性。属性修改可能只是一个值或者一个增量,也可能是一个公式id加参数。
对于共享状态,要么尽量减少它,要么就要有一定的通信手段,比如:
1.事件的订阅/发布机制
2.在产生请求时能够根据配置把对方所需的数据与命令一起发送过去
3.显式查询
4.可能还有其他办法
如果两个进程之间需要共享的东西太多,特别是需要实时共享的东西太多,那么说明两个进程耦合太大,需要从设计的层面进行考虑。
当然,这方面我也不是很在行,不过这是我学习的方向。
 
我*猜测*越复杂的东西伸缩性越难保证……只是猜测……
不过wish最终是因为性能不足导致部署成本太高,还是有其他商业上的原因?




网易邮箱,中国第一大电子邮件服务商

qiaojie

unread,
Mar 8, 2009, 12:12:03 AM3/8/09
to pon...@googlegroups.com
越说越不靠谱了,再讨论下去只是在浪费时间了,就此打住吧。


 
2009/3/8 sjinny <sji...@163.com>

sjinny

unread,
Mar 8, 2009, 1:49:52 AM3/8/09
to pon...@googlegroups.com
能否说一下哪里不靠谱呢?


网易邮箱,中国第一大电子邮件服务商

Hush

unread,
Mar 8, 2009, 7:23:15 AM3/8/09
to TopLanguage
同意楼上的同学。我不知道楼主有没有真正试过用“数据采集 ==> DB ==> 数据分析 ==> DB ==> 数据展示”来做一个健壮的项目。
用内存以外的东西来当作两个进程之前通信的方式是挺危险,且不论性能的问题,也很难保证它的正确性的。

这里的正确性是指共享数据的逻辑一致性,举例来讲,如果运行到一半的时候,进程被系统管理员误操作给kill了,你怎么保证在DB中的数据是处于一个一
致的,可以继续供其它进程来使用的。当你重启进程的时候,怎么样区分可以重用的,或者需要丢弃的数据?

使用多进程,将一个逻辑上完整的应用的各个内部的组成部分都暴露在了OS层面上,导致了更多可能受到OS影响而出错的点。这一点是削弱了健壮性的。更不
用说极大地提高了使用和维护上的成本。

而顶楼提到的多线程之前的干扰,完全可以通过一个通用的线程抽象层来加以减轻,也就是说由一个统一的模块来负责创建和启动线程,并在最外层加上
error handling,这样已经可以解决很大程度上减少影响。至于对共享数据操作导致的互相干扰,用IPC也一样会有。

至于,跨机器的部署这样的需求,是需要项目开始之前就要充分考虑的,跨machine boundary的RPC的效率和LPC不是一个量级的。很难想
像一个完全没有考虑过跨机器部署的需求的应用,只是因为用了多进程,就会可以很容易地部署到多个机器上去。

我觉得这个问题本来就是各有利弊,其实没啥好讨论的,很多时候是OS决定了的。在Windows平台上,还是多线程优先。


On 3月2日, 上午11时02分, Bennie <ZhaoYin...@gmail.com> wrote:
> 进程的崩溃和重启动远没有想象的那么简单,也需要一套复杂的实现来保证。要不就不会有系统管理员这个职位存在。
> 进程优于线程的只有存取边界和跨机器部署,隐形的优势是防止程序员抻面条。想用个全局就用全局,全无顾虑。
>

sjinny

unread,
Mar 8, 2009, 9:34:20 AM3/8/09
to pon...@googlegroups.com
我觉得“进程被系统管理员误操作给kill了”跟管理员误操作把咖啡撒进了机柜是一样的概率……进程管理是不能随随便便地操作的,linux的root用户删文件都要有额外确认的……
你所说的意外宕机导致数据的一致性被破坏的问题,对线程和进程是同样的问题。
进程内的线程同样会受os影响,我也想象不出有什么东西有本事脱离os的影响的……
“由一个统一的模块来负责创建和启动线程,并在最外层加上error handling”。如果一个线程出现bug,比如内存访问越界,结果修改了另一个模块的数据,那么这种手段能解决或防止这个问题吗?只有带有内存保护的进程才能解决这个问题。
“至于对共享数据操作导致的互相干扰,用IPC也一样会有。”你可以具体说说是哪些干扰“用IPC也一样会有”。
多进程的方案当然是要在设计阶段就做考虑的,线程也一样:一个一开始就没有考虑多线程的设计,要在半路改成多线程还要确保正确性和健壮性,我觉得也是超高难度的任务,除非原来的模块设计非常好,耦合非常低,不过这样改成多进程也不难。
os也是要做选择的,到底是根据os选择并发模型,还是根据并发模型选择os就是鸡生蛋、蛋生鸡的问题了。

网易邮箱,中国第一大电子邮件服务商

Program Thinker

unread,
Mar 8, 2009, 9:40:47 AM3/8/09
to pon...@googlegroups.com
我在原文特地写了如下一段话,但还是没有躲过数量众多的口水 :-)
由于这个问题很容易引发口水战,事先声明如下:多进程和多线程,
无法一概而论地说谁比谁好。因此本帖主要描述特定场景与我所负责的产品相关)下,进程和线程的权衡经验,仅供大伙儿参考。

对于楼上的Hush同学,我做了逐条的回答。

2009/3/8 Hush <just...@gmail.com>

同意楼上的同学。我不知道楼主有没有真正试过用“数据采集 ==> DB ==> 数据分析 ==> DB ==> 数据展示”来做一个健壮的项目。
用内存以外的东西来当作两个进程之前通信的方式是挺危险,且不论性能的问题,也很难保证它的正确性的。

我设计的产品,有采用上述DB方式的例子。不敢说非常健壮,至少还过得去吧 :-)
Hush同学认为:“用内存以外的东西来当作两个进程之前通信的方式是挺危险”。个人感觉似乎过于武断。
 

这里的正确性是指共享数据的逻辑一致性,举例来讲,如果运行到一半的时候,进程被系统管理员误操作给kill了,你怎么保证在DB中的数据是处于一个一致的,可以继续供其它进程来使用的。当你重启进程的时候,怎么样区分可以重用的,或者需要丢弃的数据?

我如果使用DB作为进程间的数据耦合方式,一般通过事务来保证一致性。
如果有某同学有更好的方法,希望能分享给大伙儿。

使用多进程,将一个逻辑上完整的应用的各个内部的组成部分都暴露在了OS层面上,导致了更多可能受到OS影响而出错的点。这一点是削弱了健壮性的。更不用说极大地提高了使用和维护上的成本。

我原文中已经提到了,对于同一个业务逻辑,如果考虑到数据交互比较多,我是倾向于使用进程内(多线程)的方式的。
而且在我负责的产品,并没有因为拆分进程(按照业务逻辑拆分)而导致Hush同学所说的“极大地提高了使用和维护上的成本”,而是恰恰相反。
如果有某同学因为拆分进程而导致
极大地提高了使用和维护上的成本,希望能拿出来与大伙儿分享一下具体情况。

而顶楼提到的多线程之前的干扰,完全可以通过一个通用的线程抽象层来加以减轻,也就是说由一个统一的模块来负责创建和启动线程,并在最外层加上 error handling,这样已经可以解决很大程度上减少影响。至于对共享数据操作导致的互相干扰,用IPC也一样会有。

个人认为:上述的方式,似乎不能有效解决扯皮的问题。
另外,对于“在最外层加上 error handling”,有些时候还是无法避免 致命的、导致崩溃的bug。

至于,跨机器的部署这样的需求,是需要项目开始之前就要充分考虑的,跨machine boundary的RPC的效率和LPC不是一个量级的。很难想
像一个完全没有考虑过跨机器部署的需求的应用,只是因为用了多进程,就会可以很容易地部署到多个机器上去。

显然,“跨机器的部署这样的需求,是需要项目开始之前就要充分考虑的”。这句话我是非常赞同的。
我认为进程的方式只是提供了跨机器的一种可能性,属于必要非充分条件。
我声明一下,我并没有说过:“因为用了多进程,就会可以很容易地部署到多个机器上去”,或者类似的话。
我原文的原话是:“
如果是以业务逻辑为单位划分进程,要满足上述的部署需求就相对容易了”。
分布式应用本来就是一个挺有难度的东东,要考虑的因素实在是很多。


我觉得这个问题本来就是各有利弊,其实没啥好讨论的,很多时候是OS决定了的。在Windows平台上,还是多线程优先。

我在原文的开头,特地强调了该产品的业务需求和应用的特点。我后面的所有讨论都是围绕该特点进行的。如果不考虑这些特点,一概而论地说哪种方式更好,比较容易陷入口水战。
我写这个帖子的本意,是希望如果有某同学碰到和我类似的场景,或许能够有所借鉴和帮助。我并不想鼓吹进程好或者线程好。

另外,如果仅仅因为是Windows平台,就优先使用线程方式,感觉理由不太充分。选择进程还是线程,我个人会更多地考虑业务需求及应用的特点,而不会优先考虑操作系统平台。


On 3月2日, 上午11时02分, Bennie <ZhaoYin...@gmail.com> wrote:
- Show quoted text -
> 进程的崩溃和重启动远没有想象的那么简单,也需要一套复杂的实现来保证。要不就不会有系统管理员这个职位存在。
> 进程优于线程的只有存取边界和跨机器部署,隐形的优势是防止程序员抻面条。想用个全局就用全局,全无顾虑。
>

--
----------------
编程随想
progra...@gmail.com
http://program-think.blogspot.com

jiang li

unread,
Mar 8, 2009, 9:49:38 PM3/8/09
to pon...@googlegroups.com


2009/3/8 Program Thinker <progra...@gmail.com>

我在原文特地写了如下一段话,但还是没有躲过数量众多的口水 :-)

由于这个问题很容易引发口水战,事先声明如下:多进程和多线程,
无法一概而论地说谁比谁好。因此本帖主要描述特定场景与我所负责的产品相关)下,进程和线程的权衡经验,仅供大伙儿参考。

对于楼上的Hush同学,我做了逐条的回答。

2009/3/8 Hush <just...@gmail.com>

同意楼上的同学。我不知道楼主有没有真正试过用“数据采集 ==> DB ==> 数据分析 ==> DB ==> 数据展示”来做一个健壮的项目。
用内存以外的东西来当作两个进程之前通信的方式是挺危险,且不论性能的问题,也很难保证它的正确性的。

我设计的产品,有采用上述DB方式的例子。不敢说非常健壮,至少还过得去吧 :-)
Hush同学认为:“用内存以外的东西来当作两个进程之前通信的方式是挺危险”。个人感觉似乎过于武断。

" a well-known folklore result that communication via message-passing can be simulated by communication via shared memory and vice-versa. Therefore, the two paradigms are equivalent."
for example, "The  shared  address  space  can  be  partitioned  into  disjoint  parts,  one  part being assigned to each processor. “Send” and “receive” operations can be implemented by writing to and reading from the destination/sender processor’s address space, respectively."
所以,共享内存和消息传递这两种模式并没有本质的区别。充其量是共享内存的方式对于大部分开发人员来说更加的熟悉。

 

这里的正确性是指共享数据的逻辑一致性,举例来讲,如果运行到一半的时候,进程被系统管理员误操作给kill了,你怎么保证在DB中的数据是处于一个一致的,可以继续供其它进程来使用的。当你重启进程的时候,怎么样区分可以重用的,或者需要丢弃的数据?

我如果使用DB作为进程间的数据耦合方式,一般通过事务来保证一致性。
如果有某同学有更好的方法,希望能分享给大伙儿。

在distributed algorithm中,有大量的算法是用来维护consistency的。而这些算法和进程还是线程一点关系都没有。

Hush

unread,
Mar 13, 2009, 2:37:14 AM3/13/09
to TopLanguage
补充2点:
1) 有一个内容我可能没有表达清楚。我的意思是使用多进程会受到OS更多的影响。我并没有说使用多线程就不会受到OS的影响。kill可能不是一个很
好的例子,但至少说明了这种可能。如果所有的practise都严格遵守,那么不管用进程还是线程,都是健壮的了。

2) 使用什么样的OS,往往是由客户,或者应用的类型决定的。包括使用什么语言之类的,我们能做的是在这样的限制条件下,选一个比较优的。

再一次申明,我并没有觉得多线程比多进程好,反之亦然,讨论这个,不如讨论分别适合在什么场景上比较有意义


On 3月8日, 下午9时34分, sjinny <sji...@163.com> wrote:
> 我觉得"进程被系统管理员误操作给kill了"跟管理员误操作把咖啡撒进了机柜是一样的概率......进程管理是不能随随便便地操作的,linux的root用户删文-件都要有额外确认的......
> 你所说的意外宕机导致数据的一致性被破坏的问题,对线程和进程是同样的问题。
> 进程内的线程同样会受os影响,我也想象不出有什么东西有本事脱离os的影响的......
> "由一个统一的模块来负责创建和启动线程,并在最外层加上error handling"。如果一个线程出现bug,比如内存访问越界,结果修改了另一个模块的数据,那么这种手段能解决或防止这个问题吗?只有带有内存保护的进程才-能解决这个问题。
> "至于对共享数据操作导致的互相干扰,用IPC也一样会有。"你可以具体说说是哪些干扰"用IPC也一样会有"。
> 多进程的方案当然是要在设计阶段就做考虑的,线程也一样:一个一开始就没有考虑多线程的设计,要在半路改成多线程还要确保正确性和健壮性,我觉得也是超高难度的-任务,除非原来的模块设计非常好,耦合非常低,不过这样改成多进程也不难。
> os也是要做选择的,到底是根据os选择并发模型,还是根据并发模型选择os就是鸡生蛋、蛋生鸡的问题了。
-

It is loading more messages.
0 new messages