现在的位置: 首页 > 综合 > 正文

轻量级线程和erlang

2013年09月19日 ⁄ 综合 ⁄ 共 1542字 ⁄ 字号 评论关闭

线程通常用来执行并行计算,为大量阻塞操作增加并发度。在线程数大于CPU数时,线程会有额外的调度开销,所以线程数太多反而会使计算性能下降。计算机执行计算任务时,通常还需要与各种IO设备交互,这些设备和CPU、内存比起来慢几个数量级,一些任务还需要串行地使用这些设备,这时候使用多线程就可以有效利用这些设备资源。

除了创建大量线程以外,还可以使用异步IO来完成同样的功能。异步IO原理上很简单,用户线程某一刻发起一个请求(对于IO来说通常只有读和写2种),在IO设备准备好的时候会回调用户指定的过程,异步IO并不阻塞和户线程,可以使用少量线程完成相同的功能。异步IO使用起来并不简单,目前大量使用的也只是网络应用。

异步IO把编程复杂化了,它要求程序必须遵从请求/回调的方式,一个完整的过程可能被分割为多个片断,程序架构非常难以控制,这时候可以引入轻量级线程解决。

轻量级线程实际上是伪线程,它是由用户来控制“线程”切换的。当一个操作需要等待异步完成时,它告诉调度器,暂停自己的执行,切换到另一个任务。当IO事件发生时,再从该断点恢复执行。在windows上,系统提供了fiber,linux上并没有相应的实现(注)。stateless python也实现了轻量级线程,著名的网络游戏EVE服务端就是使用它来实现的。其它一些语言的continuation机制也可以实现类似功能。

虽然有这么多轻量级线程的实现,但几乎都要自己进行调度,使用起来还是有相当难度的。每个“线程”中不能有阻塞操作,否则会使整个机制失效。

完美方案当然是有的,erlang可以看作是相对完美的。erlang在虚拟机上实现了轻量级线程和调度器,并且成为语言的基础。erlang里面用户并不控制线程,而是创建大量的轻量级线程,erlang里面称为进程(process),以下简称进程。每个进程都可代表一个主动对象,它有事件循环,各个进程间通过消息来通讯。一个进程向另一进程发送消息后,可以进入接收状态,这时候真正的线程会把执行权切换到其它进程,如果另一进程得到执行权,如果它回复了消息,再经过一些执行权的切换以后,原来发送消息的进程得到执行权,它就可以收到消息了,这个复杂的过程可能只需要一个线程就可以完成,程序的编写却是使用同步的方式,完全感觉不到底层的切换,你唯一需要的就是毫无顾忌地创建进程(别当真,创建几十万个就收手吧)。erlang底层通常只需要1个线程就可以完成这些复杂的工作,因为没有一个进程阻塞。在多CPU机器上,可以选择创建和CPU数目相等的进程数来提高效率。

erlang自身是完美的,但它却无法避免使用一些“不完美”的库。比如它要调用mysql,阻塞查询数据库,总不能把erlang虚拟机完全阻死吧?这个时候可以有2种选择,一种是不使用mysql的API,而是用erlang来实现mysql远程调用协议;另一种是写一个mysql调用程序,它和erlang通过网络或其它方式来通讯,接收查询指令,执行查询,并发回数据,这在erlang里面称为c node方式。

erlang里面是怎么把这些复杂的异步调用都屏蔽掉的?留给我们的竟然只是简单的同步操作方式?因为它底层就是使用异步机制,用异步操作封装了整个系统,开放给用户的是轻量级线程,完全是同步操作方式,用户不需要显式地请求线程切换,erlang虚拟机会以函数为单位进行调度,由于erlang不使用循环语句,代之以递归,所以即使是一个无限递归也不会导致其它进程不能获得执行权,erlang里面进程的调度是软实时的,它保证所有进程都能尽量平等地获得执行时间。

 

转载:http://home.51.com/cpunion/diary/item/10011940.html

抱歉!评论已关闭.