`
jack
  • 浏览: 393189 次
  • 来自: 温州
社区版块
存档分类
最新评论

Ruby的伪线程

阅读更多
    Ruby的Thread是伪线程,不管代码中写了多少个Thread.new,Ruby都只启动了一个线程去运行这些Thread的代码。

    这样做的确使得Ruby的Thread很容易控制,程序也不容易产生类似死锁这类严重的线程问题。但是效率始终无法提高,因为在ruby进程中,实际上只有一个真实的线程在运行,同样的代码在那么多核或者多cpu的电脑上运行效率和单核cpu的电脑上的效率并不会相差多少。

    于是有两个衍生问题:

    第一,不太可能用ruby编写桌面程序。桌面程序大都是单进程,多线程模型。因为ruby用的是伪线程,Thread.new用的越多,运行效率只会越来越低。CPU需要分配时间片给Ruby进程中的控制Ruby伪线程代码的Thread,然后这个Thread还要在切换运行全部的Ruby伪线程代码。所以在单进程中,Thread.new的应用数目是存在一定上限的。

    也许把Ruby代码嵌入到别的项目中就可以应用于桌面程序,不过同样,Thread.new还是不能多用。

    同样的,想用Ruby来编写一个稍高性能服务器程序,也是不行的。伪线程问题始终在制约这点。
   
    第二,Ruby项目最好采用多进程模型,只有这样才能更好的利用硬件资源。这个也是目前Ruby Web的设置方式。
    
    想让ruby运行的好,似乎只有这种办法了。不过多进程模型,除了web应用之外,还真不知道那里可以这样用,请知道更多的同学提醒下。

    当然,如果hack过ruby的源代码,说不定能够解决这个伪线程问题,不过这个难度甚高,不容易实现。
   
    最后的疑问是"Ruby为啥要用伪线程?"

   

分享到:
评论
32 楼 zhangyu8374 2007-06-19  
个人认为,在碰到用户级线程和内核线程这些概念时,一定要弄清楚线程的层次结构,弄清楚在谈论这些层次结构时所影射的参照系。参照系选择的是VM呢,还是OS,自己心中要有数。

可以看看“Solaris的线程模型”,直观明白,地址是:http://java.sun.com/docs/hotspot/threads/threads.html;

当然也可以看看“ Thread的层次结构”,地址是:http://zhangyu8374.iteye.com/blog/86297
31 楼 fixopen 2007-06-17  
问题有两个,一个是用户级线程和核心级线程如何映射的问题,一个是线程本身的控制管理问题。

如果用户级线程跟核心级线程是1:1映射的,那就意味着用户级线程这个概念是多余的,我们就可以简单的叫做线程,或者叫做1:1线程模型,它其实就是核心级线程。

如果用户级线程跟核心级线程是M:N映射的,这表明M个用户级线程映射到N个核心级线程之上,这时候,用户级线程这个概念才是必须的,才有其存在的必要,有人提出来,用户级线程只能使用一个CPU的核,这个其实是限制了N必须为1才导致的一个局限,从逻辑上讲,用户级线程没有限制自己使用CPU核的能力,虽然现在M:N的映射中N常常是1,但不表示N必须是1。

线程这个概念其实也有点演进,作为一个执行和调度的线索,其创建、销毁和调度(切换)机制是由谁实施的决定了其本身的性能和表达能力。最明显的是一个执行线索是否可以被剥夺把线程模型区分成两大类。一般来说,用户级线程是指这些机制(创建,销毁,切换和调度)是由用户级的库来实现的,而核心级显然是有OS Kernel实现这些机制的。现代的线程机制,已经不再是这么简单的一刀切的方式来实施了,而是由核心和用户共同协作来完成线程的控制管理的。由于核心可以提供全系统的事件和资源使用情况的全图,而应用一般更清楚各个线程之间的逻辑依赖关系,所以理论上也是他们合作会产生更高的效能。Activation Scheduler就是基于这个想法而出现的。简单的说:AS的想法是,线程的创建由应用提出申请,核心创建(给出一个虚拟CPU),而销毁确由应用自己决定,调度依赖于核心和用户的协作,用户可以自主调度(注意,这儿显然是不可剥夺模式的),核心在发现阻塞是可以通知应用,这时候,应用(用户级线程库)应该切换线程,这样,核心和用户协作,实现了更高性能的线程模型。
30 楼 歆渊 2006-11-01  
fixopen 写道
引用

看来你概念不清。NPTL和ruby线程是两码事。就是在Linux Kernel2.6上面跑(support NPTL),一个ruby进程里面就算有n个线程,操作系统照样只能用一个进程(一个线程)去hold,根本不可能出现1:1,除非ruby像JVM那样实现native thread,不过那还是非常遥远的事情。


虽然你是老大,但是麻烦你看清楚我说的话好不好?我什么时候说过ruby的用户级线程就是Linux的NPTL了?我说的是NPTL是1:1,而用户级线程一般叫做M:N。这里面最好的模型(我认为的)是Activation Scheduler,但是现在只有NetBSD?支持。

另外我想说的是:我已经强调了用户级线程的阻塞全局性了。所以提到多个CPU核心的人没有打中靶子。

粗略查了一下, 好像 HP-UX 11i (B.11.22), Solaris 2.6 起都有了 Scheduler Activation 机制, 其他的OS不太清楚.

另外以前就知道Solaris有Light Weight Procss, 好像也是2.6开始有的, 这个似乎比 Scheduler Activation 更进一步.
29 楼 歆渊 2006-11-01  
fixopen 写道
引用

看来你概念不清。NPTL和ruby线程是两码事。就是在Linux Kernel2.6上面跑(support NPTL),一个ruby进程里面就算有n个线程,操作系统照样只能用一个进程(一个线程)去hold,根本不可能出现1:1,除非ruby像JVM那样实现native thread,不过那还是非常遥远的事情。


虽然你是老大,但是麻烦你看清楚我说的话好不好?我什么时候说过ruby的用户级线程就是Linux的NPTL了?我说的是NPTL是1:1,而用户级线程一般叫做M:N。这里面最好的模型(我认为的)是Activation Scheduler,但是现在只有NetBSD?支持。

另外我想说的是:我已经强调了用户级线程的阻塞全局性了。所以提到多个CPU核心的人没有打中靶子。


不光是阻塞的时候吧, 不阻塞的时候也只能利用起一个CPU核心呢, 其余的都在闲置.
28 楼 fixopen 2006-11-01  
引用

看来你概念不清。NPTL和ruby线程是两码事。就是在Linux Kernel2.6上面跑(support NPTL),一个ruby进程里面就算有n个线程,操作系统照样只能用一个进程(一个线程)去hold,根本不可能出现1:1,除非ruby像JVM那样实现native thread,不过那还是非常遥远的事情。


虽然你是老大,但是麻烦你看清楚我说的话好不好?我什么时候说过ruby的用户级线程就是Linux的NPTL了?我说的是NPTL是1:1,而用户级线程一般叫做M:N。这里面最好的模型(我认为的)是Activation Scheduler,但是现在只有NetBSD?支持。

另外我想说的是:我已经强调了用户级线程的阻塞全局性了。所以提到多个CPU核心的人没有打中靶子。
27 楼 cookoo 2006-11-01  
fixopen 写道
伪线程这个名字有点……嗯……不是很好听。
这个叫做用户级线程,其优势是非常明显的,最主要的是性能奇高。当然,很多人会觉得这是瞎说。但这是真的。用户级线程也有缺陷,就是阻塞的全局性。这个缺陷导致用户级线程应用场合有限。现在,有两个模型把核心级线程和用户级线程影射起来,一个是1:1,一个是M:N。现在非常流行的是1:1方式。这也是Linux的NPTL采用的方式。

伪线程和用户级线程都是标准的英文术语,指的是同一个东西。要是Ruby有Erlang(微进程)或Haskell那样的M:N方式就好了,不过这是更加’非常遥远的事‘了
26 楼 cookoo 2006-11-01  
aardvark 写道
robbin 写道
rails的ActiveRecord不是线程安全的,如果ruby真提供了native thread的VM,那么rails的代码就得彻底大改动了,这可不是我所希望看到的。

对于运行web应用来说,其实现在ruby1.8.4用FastCGI方式运行挺好的了。也许ruby不应该遵循JavaVM曾经走过的那条路。

JRuby是native thread,它可以跑ActiveRecord。不知道他们是怎么实现的,但由此可以推断,如果Ruby将来支持native thread,ActiveRecord不会是个大问题。

不清楚jruby想用多线程方式还是多进程方式跑rails。但我很怀疑是用多线程方式跑的,Rails本身不是线程安全的,据zed shaw说meta programming也有很多线程安全问题。
25 楼 aardvark 2006-10-31  
robbin 写道
rails的ActiveRecord不是线程安全的,如果ruby真提供了native thread的VM,那么rails的代码就得彻底大改动了,这可不是我所希望看到的。

对于运行web应用来说,其实现在ruby1.8.4用FastCGI方式运行挺好的了。也许ruby不应该遵循JavaVM曾经走过的那条路。

JRuby是native thread,它可以跑ActiveRecord。不知道他们是怎么实现的,但由此可以推断,如果Ruby将来支持native thread,ActiveRecord不会是个大问题。
24 楼 robbin 2006-10-31  
fixopen 写道
伪线程这个名字有点……嗯……不是很好听。
这个叫做用户级线程,其优势是非常明显的,最主要的是性能奇高。当然,很多人会觉得这是瞎说。但这是真的。用户级线程也有缺陷,就是阻塞的全局性。这个缺陷导致用户级线程应用场合有限。现在,有两个模型把核心级线程和用户级线程影射起来,一个是1:1,一个是M:N。现在非常流行的是1:1方式。这也是Linux的NPTL采用的方式。


看来你概念不清。NPTL和ruby线程是两码事。就是在Linux Kernel2.6上面跑(support NPTL),一个ruby进程里面就算有n个线程,操作系统照样只能用一个进程(一个线程)去hold,根本不可能出现1:1,除非ruby像JVM那样实现native thread,不过那还是非常遥远的事情。
23 楼 歆渊 2006-10-31  
fixopen 写道
伪线程这个名字有点……嗯……不是很好听。
这个叫做用户级线程,其优势是非常明显的,最主要的是性能奇高。当然,很多人会觉得这是瞎说。但这是真的。用户级线程也有缺陷,就是阻塞的全局性。这个缺陷导致用户级线程应用场合有限。现在,有两个模型把核心级线程和用户级线程影射起来,一个是1:1,一个是M:N。现在非常流行的是1:1方式。这也是Linux的NPTL采用的方式。


在单CPU核心*硬线程的体系上说 "性能奇高" 是可以成立的, 但是如果用上像 SPARC T1 这种多至 8核心*4线程单元 = 32并发硬线程的系统上, 所谓的用户级线程还是把它当一个最原始的CPU在用.

即便是单核心的 Pentium 4, 也有支持HyperThread技术的两道硬线程机构.

伪线程的程序除了以多进程执行以外是没法有效利用现代的处理器资源的.
22 楼 jack 2006-10-31  
fixopen 写道
伪线程这个名字有点……嗯……不是很好听。
这个叫做用户级线程,其优势是非常明显的,最主要的是性能奇高。当然,很多人会觉得这是瞎说。但这是真的。用户级线程也有缺陷,就是阻塞的全局性。这个缺陷导致用户级线程应用场合有限。现在,有两个模型把核心级线程和用户级线程影射起来,一个是1:1,一个是M:N。现在非常流行的是1:1方式。这也是Linux的NPTL采用的方式。


能否更加详细点谈谈?
21 楼 fixopen 2006-10-31  
伪线程这个名字有点……嗯……不是很好听。
这个叫做用户级线程,其优势是非常明显的,最主要的是性能奇高。当然,很多人会觉得这是瞎说。但这是真的。用户级线程也有缺陷,就是阻塞的全局性。这个缺陷导致用户级线程应用场合有限。现在,有两个模型把核心级线程和用户级线程影射起来,一个是1:1,一个是M:N。现在非常流行的是1:1方式。这也是Linux的NPTL采用的方式。
20 楼 歆渊 2006-10-29  
robbin 写道
rails的ActiveRecord不是线程安全的,如果ruby真提供了native thread的VM,那么rails的代码就得彻底大改动了,这可不是我所希望看到的。

对于运行web应用来说,其实现在ruby1.8.4用FastCGI方式运行挺好的了。也许ruby不应该遵循JavaVM曾经走过的那条路。


记得原来偶然看到JDK代码有一段,说是修正一个bug,保证Primitive类型的原子操作的,比如一个线程在取一个 long 字段的值的时候, 不至于取了高32位以后切换到另一个线程, 正好修改了它(低32位变掉了), 再切换回来继续取低32位, 这样整个long值就是一个拼起来的数,丧失100%正确性.

看了这篇文章, 感觉Ruby一定要实现伪线程, 也许就是为了可以防止类似的并发访问陷阱. 而如果用native thread的话, 想保证100%正确性势必要在每个native thread中对每个Ruby的元操作(像取变量值, 存变量值这种)进行同步, 这个开销足以让多native thread的Ruby解释器性能降至比伪线程的解释器性能还低. 而在伪线程的方案中解释器只要选择在元操作的边界切换伪线程就可以简单的解决这个问题.

所以选择伪线程应该是解释器的局限, 如果通过VM方式执行, 就有可能在VM级别以可接受的成本实现元操作的保障.

好像主流的Ruby应用还是用解释器执行的吧? 解释执行的Ruby应该是没可能走JVM的路.
19 楼 huangyiiiiii 2006-10-29  
我想微线程的好处就是调度的开销比线程小很多很多,缺点就是不能利用多处理器优势。而线程和进程区别就是共享和不共享内存。
另外I/O模型(IO Completion Port)怎么拿来跟这些东西对比呢。当然我对完成端口也不是很了解,只知道它貌似是罕见的异步I/O模型的实现之一。
stacklesspython 是共享内存的模式,为什么是进程方式呢。它那个channel,我看主要还是用来做同步的,而传输数据的工作简单一个全局变量就可以了。
18 楼 jack 2006-10-29  
robbin 写道
rails的ActiveRecord不是线程安全的,如果ruby真提供了native thread的VM,那么rails的代码就得彻底大改动了,这可不是我所希望看到的。

对于运行web应用来说,其实现在ruby1.8.4用FastCGI方式运行挺好的了。也许ruby不应该遵循JavaVM曾经走过的那条路。


Rails的目前这种模型,大概是受到了ruby的伪线程的影响才开发的吧。不过web应用现在rails的这种方式的确很简单。就算ruby 提供了native thread也是不用修改代码的。反正都是独立进程运行的。

17 楼 bigpanda 2006-10-29  
qiezi 写道
是不是存在这样一个误解:用真正的多线程会提高效率?用伪线程才会降低效率?

一个操作系统中运行的线程超过CPU数量就可能有线程切换,线程越多,效率就越低,让我们感觉到多线程高效是因为它让一些同步IO延时变得不那么明显了。

在单CPU时,如果有完整的异步IO支持,线程并不是必要的,线程本身是为了简化异步IO调用才需要的。异步IO在很多操作系统中都是最基本的实现,很多同步调用是用异步来模拟的。多CPU时,用多进程也可以充分利用CPU资源。


一个服务器程序,启动一个线程池,对每一个客户请求由一个线程处理,这是最常见的模式。的确,线程池启动上百个线程,每个线程自己的Stack要占有内存空间,切换线程要花费CPU时间,效率不高。但这不是线程的唯一模式。

在Windows下有一种模式叫IO Completion Port,启动的线程数量,和CPU数量相同,编程模式复杂些,但是负载量非常高。有兴趣可以去Google查查。

多进程模式在进程之间的通讯(Inter process communication)开销太大。没有同一进程内两个线程通讯方便。
16 楼 cookoo 2006-10-28  
Stackless python自称microthread,不过编程模型怎么看都是进程方式。
15 楼 robbin 2006-10-28  
rails的ActiveRecord不是线程安全的,如果ruby真提供了native thread的VM,那么rails的代码就得彻底大改动了,这可不是我所希望看到的。

对于运行web应用来说,其实现在ruby1.8.4用FastCGI方式运行挺好的了。也许ruby不应该遵循JavaVM曾经走过的那条路。
14 楼 jack 2006-10-28  
buaawhl 写道


回到 Ruby 的线程模型。
stackless python 的线程模型是怎样的? 也是 native thread ?
伪线程模型是否应该更容易应对多核CPU?


stackless python  似乎不错  eve的服务器就是用这个开发的。
这个也是伪线程模型?
13 楼 buaawhl 2006-10-28  
charon 写道

Erlang的轻量级进程模型唯一的进程间通讯方式是消息机制。进程内容在相互之间是完全解耦的,要进行数据交换共享必须通过进程间通讯.
线程模型不一样,不论是伪线程还是native线程,允许共享数据.
这个会在实现模式和编程模型上带来很大区别


Yes.
比如,message passing without shared data,  non destructive variable 这些。如果按照单线程的性能来算,ErLang的效率不高。
Erlang VM 相当于把一些编程复杂度转嫁到程序员身上,才换来了高并发。幸亏,还有一个 Pattern Match 的语法亮点,能够抵消一下这些多出来的复杂度。

--------------------

回到 Ruby 的线程模型。
stackless python 的线程模型是怎样的? 也是 native thread ?
伪线程模型是否应该更容易应对多核CPU?

相关推荐

    积分java源码-CreditsCPlusPlusDemoCMake:在C++(CMake)中使用CREDITSAPI

    编程语言的一组库,为线性代数、伪随机数生成、多线程、图像处理、正则表达式和单元测试等任务和结构提供支持。 它包含八十多个单独的库。 CMake 是一个开源、跨平台的工具系列,旨在构建、测试和打包软件。 CMake ...

    大数据面试题(1).docx

    29. **Map槽与线程**:在MapReduce中,每个map槽对应一个单独的线程,用于执行map任务。 30. **Input Split与Block关系**:MapReduce的input split通常基于HDFS的Block来划分,但可以自定义split逻辑。 31. **...

    大数据面试题(1).doc

    29. **Map槽与线程**:每个map槽代表一个处理任务的线程。 30. **Input Split与Block关系**:在MapReduce中,input split通常对应于一个或多个HDFS的Block。 31. **NameNode Web UI**:NameNode的Web UI默认运行在...

    大数据面试题 (2).pdf

    - 解析:MapReduce提供了多种语言的API,如Python、Ruby等。 19. Hadoop是否支持数据的随机读写? - 答案:不直接支持,HDFS设计为顺序读写优化。 - 解析:HDFS主要设计用于大规模批处理,不擅长随机读写。 20....

    大数据面试题.pdf

    29. **map槽与线程**:每个map槽对应一个并行处理任务,不一定是线程,取决于具体实现。选项部分正确。 30. **Input Split与Block**:MapReduce的Input Split可以是Block或其子集,不一定是完整的Block。选项部分...

    大数据技术Hadoop笔试题.doc.pdf

    29. **Map槽与线程**:每个map槽通常对应一个线程,用于执行map任务(答案正确)。 30. **Input Split与Block**:MapReduce的input split通常基于Block,但并不完全等同,split可以根据输入格式被划分为更小的单位...

    大数据技术Hadoop面试题 (2).pdf

    18. Hadoop虽然主要是用Java开发,但MapReduce也支持其他编程语言,如Python和Ruby,所以这个判断题是错误的。 19. NameNode确实管理metadata,但metadata通常驻留在内存中,而不是每次读写都从磁盘读取或写入,...

    Hadoop面试100题.pdf

    - **知识点说明**:虽然Hadoop核心是由Java编写的,但MapReduce作业可以用多种编程语言编写,包括Python、Ruby等,通过相应的API实现。 7. **Hadoop支持数据的随机读写** - **知识点说明**:HDFS主要设计用于流式...

    消息事件说明文档

    - `Session`:代表一个发送或接收消息的独立线程上下文。 - `MessageProducer`:用于发送消息到指定目的地。 - `MessageConsumer`:用于接收来自特定目的地的消息。 **3.2 对象之间的关系** - 创建`...

    springCloud

    这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。 断路器示意图 SpringCloud Netflix实现了断路器库的名字叫Hystrix. 在微服务架构下,通常会有多个层次的服务调用. 下面是...

Global site tag (gtag.js) - Google Analytics