- 浏览: 268136 次
- 性别:
- 来自: 杭州
最新评论
-
pjsong3101:
引用 public static void main ...
JVM中可生成的最大Thread数量 -
lzp459260276:
RabbitMQ源码分析 – 消息生命周期 -
huotianjun:
关于:为什么要每个操作写一个信息,而不是在publish时写一 ...
RabbitMQ源码分析 – 持久化机制 -
puyongjun_1989:
楼主你好, (256 * 1024) / 64 = 409 ...
JVM中可生成的最大Thread数量 -
chuqingq:
很不错,学习!
Erlang并发机制 –进程调度
在了解Erlang的并发机制之前,我们先来看一下Erlang与Java的并发性能对比,一个是并发单元的创建时间,一个是并发单元之间的消息通讯时间(纵坐标代表时间,横坐标代表并发数量):
(测试程序及说明见这里,原测试时间比较早了,于是在自己的虚拟机上重新跑了下(CenterOS 6,3G内存);JVM生成线程数量控制,可见这里,)
从上面的测试结果来看,Erlang的并发效率要比Java好很多,不在一个数量级上,Erlang是Java的1000倍左右(这不能说明在所有场景下Erlang的并发性能都优于Java,比如消息传递方面,消息的大小可能对这个结果也有影响)。那么Erlang的并发机制相比Java到底好在哪里,本文及后续几篇文章的目的就是搞清楚这个问题。
在《Erlang 编程指南》一书中,对Erlang的并发单元,进程的解释如下:
“Erlang进程是轻量级进程,它的生成、上下文切换和消息传递是由虚拟机管理的。操作系统线程的Erlang进程之间没有任何联系,这使并发有关的操作不仅独立于底层的操作系统,而且也是非常高效和具有很强可扩展性。”
由此可见,Erlang里的进程跟操作系统里常提到的进程,线程完全没有关系,只是Erlang并发机制里基本并发单元的一个代称。下面详细的说明Erlang进程的创建过程。
从Erlang虚拟机的角度来看,Erlang进程就是一个process结构,定义在$OTP_SRC/erts/emulator/beam/erl_process.h中(struct process),该结构中包含进程所使用的堆栈、GC、调度、消息队列等信息。Erlang程序通过erlang:spawn或者相关BIF调用(spawn_opt,spawn_link等)可以生成一个新的进程。
在erts中,spawn调用会最终调用到spawn_3:
[$OTP_SRC/erts/emulator/beam/bif.c --> spawn_3]
pid = erl_create_process(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, &so);
首先就是调用erl_create_process来生成一个新的进程,会返回创建进程的pid。我们来看看erl_create_process具体都做了哪些事情。
[$OTP_SRC/erts/emulator/beam/erl_process.c --> erl_create_process]
// 参数说明 Eterm erl_create_process(Process* parent, /* Parent of process (default group leader). */ Eterm mod, /* Tagged atom for module. */ Eterm func, /* Tagged atom for function. */ Eterm args, /* Arguments for function (must be well-formed list). */ ErlSpawnOpts* so) /* Options for spawn. */ // 首先调用alloc_process分配一个process结构需要的内存空间 p = alloc_process(); /* All proc locks are locked by this thread on success */ if (!p) { // 如果p==null,则说明系统中进程数量已达到上限 so->error_code = SYSTEM_LIMIT; goto error; } /* Scheduler queue mutex should be locked when changeing * prio. In this case we don't have to lock it, since * noone except us has access to the process. */ // 设置process的最小堆大小 if (so->flags & SPO_USE_ARGS) { //以参数值设置堆属性,一般通过erlang:spawn_opt调用传入参数 p->min_heap_size = so->min_heap_size; // 最小堆内存 p->min_vheap_size = so->min_vheap_size; // 最小虚拟堆内存 //(用于存放二进制数据) p->prio = so->priority; // 进程优先级(max, high, normal, low) p->max_gen_gcs = so->max_gen_gcs; // full gc之前可进行的minor gc的最大次数 } else { // 按默认值设置:H_MIN_SIZE=233 (fib(11),erlang里的堆内存按照fib系列增长, // 具体可参见[$OTP_SRC/erts/emulator/beam/erl_c.c --> erts_init_gc]里的说明) p->min_heap_size = H_MIN_SIZE; p->min_vheap_size = BIN_VH_MIN_SIZE; // 默认值32768(216) p->prio = PRIORITY_NORMAL; p->max_gen_gcs = (Uint16) erts_smp_atomic32_read_nob(&erts_max_gen_gcs); } // 创建进程时传入的module,function,和参数的数量 p->initial[INITIAL_MOD] = mod; p->initial[INITIAL_FUN] = func; p->initial[INITIAL_ARI] = (Uint) arity; /* * Must initialize binary lists here before copying binaries to process. */ p->off_heap.first = NULL; p->off_heap.overhead = 0; // 计算初始需要的heap大小 heap_need += IS_CONST(parent->group_leader) ? 0 : NC_HEAP_SIZE(parent->group_leader); if (heap_need < p->min_heap_size) { sz = heap_need = p->min_heap_size; } else { /* * Find the next heap size equal to or greater than the given size (if offset == 0). * * If offset is 1, the next higher heap size is returned (always greater than size). */ sz = erts_next_heap_size(heap_need, 0); } // 分配进程堆内存 p->heap = (Eterm *) ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP, sizeof(Eterm)*sz); p->old_hend = p->old_htop = p->old_heap = NULL; // 进程堆内存里年轻代的标志位:地址小于此标志位的,是较老的年轻代(一般情况 // 下,这些对象至少经过了一次minor gc或者major gc);大于这个地址的是较年轻的 // 年轻代。 p->high_water = p->heap; // minor gc的次数 p->gen_gcs = 0; // 栈顶,紧邻堆 p->stop = p->hend = p->heap + sz; p->htop = p->heap; p->heap_sz = sz; /* No need to initialize p->fcalls. */ // 当前模块及函数信息 p->current = p->initial+INITIAL_MOD; // 第一条指令设置为i_apply p->i = (BeamInstr *) beam_apply; // cp保存进入一个函数调用时,当前函数的下一条指令 p->cp = (BeamInstr *) beam_apply+1; // 消息队列 p->msg.first = NULL; p->msg.last = &p->msg.first; p->msg.save = &p->msg.first; p->msg.len = 0; #ifdef ERTS_SMP // 消息进入队列 p->msg_inq.first = NULL; p->msg_inq.last = &p->msg_inq.first; p->msg_inq.len = 0; p->bound_runq = NULL; if (so->flags & SPO_LINK) { // 进程链接,由spawn_link指定 if (IS_TRACED_FL(parent, F_TRACE_PROCS)) { trace_proc(parent, parent, am_link, p->id); } // 父进程及当前进程互相连接 erts_add_link(&(parent->nlinks), LINK_PID, p->id); erts_add_link(&(p->nlinks), LINK_PID, parent->id); } /* * Test whether this process should be initially monitored by its parent. */ if (so->flags & SPO_MONITOR) { Eterm mref; //进程监控:单向,由spawn_monitor指定 mref = erts_make_ref(parent); erts_add_monitor(&(parent->monitors), MON_ORIGIN, mref, p->id, NIL); erts_add_monitor(&(p->monitors), MON_TARGET, mref, parent->id, NIL); so->mref = mref; } /* * Schedule process for execution. */ if (!((so->flags & SPO_USE_ARGS) && so->scheduler)) // 如果参数中未指定scheduler,则使用父进程的任务队列 rq = erts_get_runq_proc(parent); else { // 根据绑定的scheduler,获取任务队列(spawn_opt中可以绑定scheduler,文档 // 中无说明,具体可见:[$OTP_SRC/erts/emulator/beam/bif.c --> spawn_opt_1]) int ix = so->scheduler-1; ASSERT(0 <= ix && ix < erts_no_run_queues); rq = ERTS_RUNQ_IX(ix); p->bound_runq = rq; } #ifdef ERTS_SMP // 设置当前进程的任务队列 p->run_queue = rq; #endif // 设置进程的状态为waiting p->status = P_WAITING; // 将当前进程添加到任务队列,并将进程的状态设置为runnable notify_runq = internal_add_to_runq(rq, p); // 唤醒调度器 smp_notify_inc_runq(notify_runq); // 返回进程PID res = p->id; // 创建成功 VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->id));
进程创建成功后,会将pid返回到spawn_3调用。
[$OTP_SRC/erts/emulator/beam/bif.c --> spawn_3]
if (ERTS_USE_MODIFIED_TIMING()) { BIF_TRAP2(erts_delay_trap, BIF_P, pid, ERTS_MODIFIED_TIMING_DELAY); } BIF_RET(pid);
BIF_TRAP2是Erlang里的Trap机制,关于Trap机制的详细说明见这里。这里的调用属于第三类,主动放弃CPU。erts_delay_trap最终会以以pid和ERTS_MODIFIED_TIMING_DELAY()为参数调用erlang:delay_trap。ERTS_USE_MODIFIED_TIMING()这个宏成立的条件是modified timing开关打开,具体参数erl的+T参数,默认未打开。更详细的说明见这里。
[$OTP_SRC/ erts/preloaded/src /erlang.erl --> erlang:delay_trap]
%% %% Trap function used when modified timing has been enabled. %% delay_trap(Result, 0) -> erlang:yield(), Result; delay_trap(Result, Timeout) -> receive after Timeout -> Result end.erlang:yield等同于receive after 1 -> Result end,delay_trap的作用就是让当前进程放弃CPU,使其它的进程有机会运行,在spawn调用的场景下,也就是会使新创建的进程有机会被调度到。
发表评论
-
RabbitMQ源码分析 – 持久化机制
2012-08-21 09:34 14691(注:分析代码基于Rabb ... -
RabbitMQ源码分析 - 队列机制
2012-07-09 10:10 13306(注:分析代码基于RabbitMQ 2.8.2) 当r ... -
RabbitMQ源码分析 – 消息生命周期
2012-06-25 10:53 9980(注:分析代码基于Rabb ... -
RabbitMQ源码分析 – 实体初始化
2012-06-11 16:15 6303(注:分析代码基于RabbitMQ 2.8.2) Con ... -
RabbitMQ源码分析 – 网络层
2012-05-30 13:31 8551(注:分析代码基于Rabb ... -
RabbitMQ源码分析 - 启动
2012-05-24 19:41 8780RabbitMQ是一个消息队列的实现,基于AMQP(Ad ... -
Erlang热部署 – 模块更新
2012-05-21 10:55 5148Erlang的热部署做的很完善,参见Release Hand ... -
Erlang并发机制 – 垃圾回收
2012-05-02 10:34 3903Erlang中每个进程都有独立的堆内存,默认的大小是23 ... -
Erlang并发机制 – 消息传递
2012-05-02 10:24 7517Erlang系统中,进程之间的通信是通过消息传递来完成的 ... -
Erlang并发机制 – 任务迁移算法
2012-05-02 10:22 3111一般情况下,在SMP环 ... -
Erlang并发机制 –进程调度
2012-04-10 22:43 9001Erlang调度器主要完成对Erlang进程的调度,它是 ... -
CentOS6下编译Erlang R15B with wxWidgets
2012-02-23 16:41 19362如果不需要安装wxWidgets的话,很简单,./con ... -
Tsung源码分析(五):Tsung数据统计
2012-02-22 19:59 3035上一篇说明Tsung的服务器监控机制的时候提到,收集到监 ... -
Tsung源码分析(四):Tsung服务器监控
2012-02-21 22:18 4474Tsung在进行压力测试同时,也可以监控服务器结点上的C ... -
Tsung源码分析(三):Tsung插件式协议支持
2012-02-17 16:15 5119在Websocket for Tsung一文中有提到如 ... -
Tsung源码分析(二):Tsung压力生成过程
2012-02-17 12:55 3694上一篇讲到ts_config_server:newbeams通 ... -
Tsung源码分析(一):Tsung启动过程
2012-02-17 12:51 6841一方面,分析Tsung的架 ... -
Websocket for Tsung
2012-02-11 22:11 5721这篇博文距离上次提到要写差不多快两个月了,一方面时间不多 ... -
Windows下vimerl的配置以及扩展
2011-12-11 22:03 3598最近开始学习Erlang,一方面出于对其主要语言特征(高 ...
相关推荐
Erlang是一种高级编程语言,特别适用于并发、分布式和实时计算系统。它的设计目标是创建一个高度可靠且容错的环境,广泛应用于电信、金融、在线游戏和消息队列服务等领域。Erlang由爱立信开发,其核心概念包括进程...
1. **并发**:Erlang的轻量级进程和并行执行使得处理大量并发连接变得简单。 2. **热代码替换**:允许在运行时更新代码,无需停止系统服务,这对持续运行的服务如RabbitMQ非常有用。 3. **分布式**:Erlang节点可以...
Erlang之所以成为RabbitMQ的首选语言,是因为其内置的并发机制、分布式特性以及错误恢复能力。Erlang的BEAM虚拟机(Erlang虚拟机)允许在单个进程中创建大量轻量级线程,称为进程,这些进程之间的通信高效且易于实现...
Erlang是一款强大的编程语言,尤其在分布式计算、并发处理和实时...Erlang的特性如轻量级进程、消息传递和错误恢复机制使得它在构建高可用性、容错性强的系统中备受青睐,特别是在电信、互联网服务和大数据处理等领域。
1. **轻量级进程**:Erlang中的进程非常轻便,消耗资源少,可以实现大量并发处理,适合构建高并发、高可用性的系统。 2. **分布式计算**:Erlang节点间可以通过网络进行通信,允许在多台机器上分布运行程序,提高了...
这种并发机制使得Erlang在处理高并发场景时表现出色,如大规模在线服务和实时通信系统。 2. **分布式**:Erlang天生支持分布式计算,可以在多台机器上无缝运行,节点间通信高效而可靠,为构建分布式系统提供了便利...
● 并发性 - Erlang支持超大量级的并发进程,并且不需要操作系统具有并发机制。 ● 分布式 - 一个分布式Erlang系统是多个Erlang节点组成的网络(通常每个处理器被作为一个节点) ● 健壮性 - Erlang具有多种基本的...
Erlang是一种面向并发、分布式、容错的编程语言,常用于构建高可用性和高并发性的系统,而Java则是一种广泛应用的通用编程语言,广泛应用于企业级应用开发。描述中提到该示例已经过测试且易于理解,这意味着我们将...
在Erlang 19.0.4中,开发者可以利用其强大的并发特性来构建高可用性系统,因为Erlang的进程模型允许数千个轻量级进程在同一时间运行。此外,Erlang虚拟机(BEAM)提供了垃圾回收机制,确保了内存管理的效率。Erlang...
7. **并发和进程管理**:Erlang的并发模型基于轻量级进程(LWP),手册会讲解如何创建、通信和管理进程,以及如何利用`spawn`、`send`、`receive`等机制。 8. **性能和监控**:通过`observer`工具和其他监控模块,...
Erlang是一种高级编程语言,特别为并发、分布式计算和容错设计,广泛应用于网络通信、实时系统和大型分布式计算环境中。最新版的Erlang是23.3.4.3-1.el7.x86_64.rpm,这个版本针对CentOS 7进行了优化。Erlang以其轻...
1. 并发与分布式计算:ffl-erl充分利用Erlang的轻量级进程和消息传递机制,实现高效的并发处理。这使得在多客户端环境中,模型的同步和更新过程可以高效且低延迟地进行。 2. 功能性编程:Erlang的函数式编程风格...
Erlang是一种为构建并发和分布式系统设计的编程语言,它特别适用于需要高可靠性和高可用性的场景,例如电信、银行和即时通讯系统等。这份文档通过一系列例子详细展示了Erlang语言的核心概念,如进程通信、模式匹配、...
它通过轻量级进程(Lightweight Processes, LWP)实现并发,这些进程消耗的资源很少,使得系统能同时运行大量进程而不会导致性能下降。 2. **分布式计算**:Erlang OTP支持跨节点的分布式计算,使得开发者可以构建...
进程间通信是Erlang并发模型的核心部分。进程之间通过发送和接收消息来协调工作。每个进程都有一个消息队列,当进程接收到消息时,它可以决定如何响应。 **5.3 超时** 超时机制允许进程在等待消息时设置时间限制。...
Erlang的并发模型基于轻量级进程,它们之间的通信通过消息传递完成。这种模型非常适合游戏服务器,因为游戏通常涉及大量并发用户交互。同时,Erlang的分布式特性允许我们在多台机器上无缝地扩展游戏服务器,以应对高...
- Erlang OTP(开放电信平台)是一套设计模式和库,用于构建高度并发、容错的系统。`ssl`库作为OTP的一部分,其修改可能遵循了OTP的设计原则,如进程间通信(IPC)、故障恢复和分布式系统的可靠性。 3. **SSL/TLS...
Erlang的并发模型基于进程,每个进程都有自己的堆栈和局部变量,进程间通过异步消息传递进行通信,这样的设计保证了高并发场景下的低延迟和高效率。 OTP框架在Erlang之上提供了一系列库、设计原则和开发工具,用于...
在《Erlang并发编程》一书中,详细介绍了Erlang语言的核心并发模型和编程范式,包括但不限于串行编程、进程创建、进程间通信、分布式编程以及错误处理等。书中指出Erlang的并发性能得益于其轻量级进程,这些进程是由...