[Erlang 0076] Erlang Shell一个怪问题

简介:

 最近一直在忙,偶尔有点时间在读书,补充一下能量;最近在学习 程序设计语言-实践之路 非常感慨,之前误打误撞的一点所得原来有一个更系统,完整的知识体系;于是沉下心来,慢慢吸收.像北上广这样的城市快速的代谢着我们的精力和知识,不容懈怠,不过倒也不必急躁,如果心浮气躁,效果必然大打折扣;抽时间整理一下最近的笔记,先从一个怪异的问题开始吧!

 

  在Erlang shell中我常常创建一个无限等待接收消息的进程来做一些测试,代码:spawn(fun() -> receive after infinity-> io:format("DONE!") end end).问题复现步骤:1.在Erlang Shell中启动这个进程之后 2.向该进程发送消息 3.由于没有消息提取的逻辑,该进程收到的消息就会积压在消息队列里面,可以通过erlang:process_info查看;首先使用Shell进程来试一下,可以看到结果是和我们的预期一致的:

 

 

复制代码
23> [self()!abc || _<-lists:seq(1,20)].
[abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,
abc,abc,abc,abc,abc,abc]
24> erlang:process_info(self()).      
[{current_function,{erl_eval,do_apply,6}},
{initial_call,{erlang,apply,2}},
{status,running},
{message_queue_len,20},
{messages,[abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,abc,
            abc,abc,abc,abc,abc,abc,abc,abc]},
{links,[<0.26.0>]},
{dictionary,[]},
{trap_exit,false},
{error_handler,error_handler},
{priority,normal},
{group_leader,<0.25.0>},
{total_heap_size,5168},
{heap_size,2584},
{stack_size,24},
{reductions,68319},
{garbage_collection,[{min_bin_vheap_size,46368},
                      {min_heap_size,233},
                      {fullsweep_after,65535},
                      {minor_gcs,16}]},
{suspending,[]}] 
复制代码
   下面我们使用spawn(fun)的方式试一下,看下面的结果,在发送了两条消息之后查看进程状态,发现消息队列是空的!!!

 

复制代码
Erlang R15B (erts-5.9) [source] [64-bit] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9  (abort with ^G)
1> P=spawn(fun() -> receive after infinity-> io:format("dONE!") end end).
<0.34.0>
2> P!abc.
abc
3> P!abcd.
abcd
4> erlang:process_info(P).
[{current_function,{erl_eval,receive_clauses,8}},
{initial_call,{erlang,apply,2}},
{status,waiting},
{message_queue_len,0},
{messages,[]},
{links,[]},
{dictionary,[]},
{trap_exit,false},
{error_handler,error_handler},
{priority,normal},
{group_leader,<0.25.0>},
{total_heap_size,233},
{heap_size,233},
{stack_size,10},
{reductions,26},
{garbage_collection,[{min_bin_vheap_size,46368},
                      {min_heap_size,233},
                      {fullsweep_after,65535},
                      {minor_gcs,0}]},
{suspending,[]}]
复制代码

 

 
 难道是这样的写法在Erlang Shell中有问题?我就把这段代码放在一个测试模块中试一下:
复制代码
-module(t).
-compile(export_all).

a() -> 
    receive 
         {Data}-> io:format("reveive Data :~p~n ",[Data]),
         a()
    after infinity ->
          io:format("Done!")
    end.

b() -> spawn(fun() -> receive after infinity-> io:format("dONE!") end end). 
复制代码
 
运行上面的代码t:b(),发送消息,然后查看进程状态,$$$$~~~~~~,看到了没有,这种写法消息队列里面是可以看到积压的消息的!! 那么之前的写法,接收到的消息在哪里呢?

 

复制代码
5> t:b().
<0.39.0>
6> v(5)!abc.
abc
7> v(5)!abcd.
abcd
8> erlang:process_info(v(5)).
[{current_function,{t,'-b/0-fun-0-',0}},
{initial_call,{erlang,apply,2}},
{status,waiting},
{message_queue_len,2},
{messages,[abc,abcd]},
{links,[]},
{dictionary,[]},
{trap_exit,false},
{error_handler,error_handler},
{priority,normal},
{group_leader,<0.25.0>},
{total_heap_size,233},
{heap_size,233},
{stack_size,0},
{reductions,2},
{garbage_collection,[{min_bin_vheap_size,46368},
                      {min_heap_size,233},
                      {fullsweep_after,65535},
                      {minor_gcs,0}]},
{suspending,[]}]
复制代码

 

   消息有可能在哪里呢?还有一个办法,我们把stacktrace输出一下,从下面的结果中我们可以看到一点端倪:进程P的堆栈信息中y(2) [abcd,abc]就是之前我们香它发送的消息;查看一下t:b()进程,并没有看到类似的信息;通过对比,突破点应该在这里,但是苦于没有找到process_dsiplay输出信息的详细说明,难以继续了,记录于此,日后继续

复制代码
9> bt(P).
Program counter: 0x00007f738b7d76c0 (erl_eval:receive_clauses/8 + 168)
CP: 0x0000000000000000 (invalid)
arity = 0

0x00007f738d11c2d0 Return addr 0x000000000084e1b8 (<terminate process normally>)
y(0)     []
y(1)     value
y(2)     [abcd,abc]
y(3)     {value,#Fun<shell.7.20862592>}
y(4)     {eval,#Fun<shell.24.20862592>}
y(5)     []
y(6)     {[{call,1,{remote,1,{atom,1,io},{atom,1,format}},[{string,1,"dONE!"}]}],[]}
y(7)     []
y(8)     infinity
ok
10> bt(v(5)).
Program counter: 0x00007f73852f7ec0 (t:'-b/0-fun-0-'/0 + 8)
CP: 0x000000000084e1b8 (<terminate process normally>)
arity = 0
ok
11> 

复制代码

 

最后贴张图,今年银河印象的作品 车手

目录
相关文章
|
Web App开发 Shell Linux
|
2月前
|
存储 安全 Unix
七、Linux Shell 与脚本基础
别再一遍遍地敲重复的命令了,把它们写进Shell脚本,就能一键搞定。脚本本质上就是个存着一堆命令的文本文件,但要让它“活”起来,有几个关键点:文件开头最好用#!/usr/bin/env bash来指定解释器,并用chmod +x给它执行权限。执行时也有讲究:./script.sh是在一个新“房间”(子Shell)里跑,不影响你;而source script.sh是在当前“房间”里跑,适合用来加载环境变量和配置文件。
412 9
|
2月前
|
存储 Shell Linux
八、Linux Shell 脚本:变量与字符串
Shell脚本里的变量就像一个个贴着标签的“箱子”。装东西(赋值)时,=两边千万不能有空格。用单引号''装进去的东西会原封不动,用双引号""则会让里面的$变量先“变身”再装箱。默认箱子只能在当前“房间”(Shell进程)用,想让隔壁房间(子进程)也能看到,就得给箱子盖个export的“出口”戳。此外,Shell还自带了$?(上条命令的成绩单)和$1(别人递进来的第一个包裹)等许多特殊箱子,非常有用。
299 2
|
5月前
|
Shell
Shell脚本循环控制:shift、continue、break、exit指令
使用这些命令可以让你的Shell脚本像有生命一样动起来。正确使用它们,你的脚本就能像一场精心编排的舞蹈剧目,既有旋律的起伏,也有节奏的跳跃,最终以一场惊艳的表演结束。每一个动作、每一个转折点,都准确、优雅地完成所需要表达的逻辑。如此,你的脚本不只是冰冷的代码,它透过终端的界面,跳着有节奏的舞蹈,走进观众——使用者的心中。
264 60