[Erlang 0041] 详解io:format
%%代码路径:\erl5.9\lib\stdlib-1.18\src\io.erl format(Format) -> format(Format, []). format(Format, Args) -> format(default_output(), Format, Args). format(Io, Format, Args) -> o_request(Io, {format,Format,Args}, format).
default_output() -> group_leader().
group_leader() -> GroupLeader
Types:
GroupLeader = pid()
Returns the pid of the group leader for the process which evaluates the function.
Every process is a member of some process group and all groups have a group leader. All IO from the group is channeled to the group leader. When a new process is spawned, it gets the same group leader as the spawning process. Initially, at system start-up, init is both its own group leader and the group leader of all processes.
Eshell V5.9 (abort with ^G)1> self(). <0.30.0>2> P=spawn(fun()-> receive after infinity -> hello end end ). <0.33.0>3> 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.23.0>}, %%注意这里就是进程P的group leader {total_heap_size,233}, {heap_size,233}, {stack_size,10}, {reductions,18}, {garbage_collection,[{min_bin_vheap_size,46368}, {min_heap_size,233}, {fullsweep_after,65535}, {minor_gcs,0}]}, {suspending,[]}]4> erlang:process_info(pid(0,23,0)). %%继续跟进看看P进程的group leader是什么样的进程? [{registered_name,user}, %%注意P进程的group leader的registered_name是user!!! {current_function,{user,server_loop,2}}, {initial_call,{erlang,apply,2}}, {status,waiting}, {message_queue_len,0}, {messages,[]}, {links,[<0.21.0>,<0.24.0>,#Port<0.319>,<0.5.0>]}, {dictionary,[{unicode,false}, {read_mode,list}, {shell,<0.24.0>}]}, {trap_exit,true}, {error_handler,error_handler}, {priority,normal}, {group_leader,<0.23.0>}, %%user进程的group leader就是它自己 {total_heap_size,3194}, {heap_size,2584}, {stack_size,9}, {reductions,1310}, {garbage_collection,[{min_bin_vheap_size,46368}, {min_heap_size,233}, {fullsweep_after,65535}, {minor_gcs,2}]}, {suspending,[]}]5> whereis(init). %%观察下init进程的元数据 <0.0.0>6> erlang:process_info(pid(0,0,0)). [{registered_name,init}, {current_function,{init,loop,1}}, {initial_call,{otp_ring0,start,2}}, {status,waiting}, {message_queue_len,0}, {messages,[]}, {links,[<0.5.0>,<0.6.0>,<0.3.0>]}, {dictionary,[]}, {trap_exit,true}, {error_handler,error_handler}, {priority,normal}, {group_leader,<0.0.0>},%init的group leader 就是它自己 {total_heap_size,1974}, {heap_size,1597}, {stack_size,2}, {reductions,2357}, {garbage_collection,[{min_bin_vheap_size,46368}, {min_heap_size,233}, {fullsweep_after,65535}, {minor_gcs,4}]}, {suspending,[]}]7> erlang:process_info(pid(0,30,0)). %调转回头我们看看当前这个shell的group leader [{current_function,{erl_eval,do_apply,6}}, {initial_call,{erlang,apply,2}}, {status,running}, {message_queue_len,0}, {messages,[]}, {links,[<0.24.0>]}, {dictionary,[]}, {trap_exit,false}, {error_handler,error_handler}, {priority,normal}, {group_leader,<0.23.0>}, %还记得这是什么进程的进程ID? 对,是user {total_heap_size,3571}, {heap_size,2584}, {stack_size,24}, {reductions,18941}, {garbage_collection,[{min_bin_vheap_size,46368}, {min_heap_size,233}, {fullsweep_after,65535}, {minor_gcs,6}]}, {suspending,[]}]8> self(). %%下面我们要把当前shell搞崩 <0.30.0>9> 1/0. ** exception error: bad argument in an arithmetic expressionin operator '/'/2 called as 1 / 010> self(). %%再次查看 Shell的pid已经变了 <0.41.0>11> erlang:process_info(pid(0,41,0)). [{current_function,{erl_eval,do_apply,6}}, {initial_call,{erlang,apply,2}}, {status,running}, {message_queue_len,0}, {messages,[]}, {links,[<0.24.0>]}, {dictionary,[]}, {trap_exit,false}, {error_handler,error_handler}, {priority,normal}, {group_leader,<0.23.0>}, %%注意这里的group leader 还是shell {total_heap_size,3571}, {heap_size,2584}, {stack_size,24}, {reductions,3281}, {garbage_collection,[{min_bin_vheap_size,46368}, {min_heap_size,233}, {fullsweep_after,65535}, {minor_gcs,8}]}, {suspending,[]}]12>
userStandard I/O ServerDESCRIPTIONuser is a server which responds to all the messages defined in the I/O interface. The code in user.erl can be used as a model for building alternative I/O servers.
%%代码路径\erl5.9\lib\kernel-2.15\src\user.erl run(P) -> put(read_mode,list), put(unicode,false), case init:get_argument(noshell) of %% non-empty list -> noshell {ok, [_|_]} -> put(shell, noshell), server_loop(P, queue:new()); _ -> group_leader(self(), self()), catch_loop(P, start_init_shell()) end.
group_leader(GroupLeader, Pid) -> true
Types:
GroupLeader = Pid = pid()Sets the group leader of Pid to GroupLeader. Typically, this is used when a processes started from a certain shell should have another group leader than init.
See also group_leader/0.
%%代码路径:\erl5.9\lib\stdlib-1.18\src\io.erl o_request(Io, Request, Func) -> case request(Io, Request) of %这里的Io参数的值就是group_leader哦 {error, Reason} -> [_Name | Args] = tuple_to_list(to_tuple(Request)), {'EXIT',{get_stacktrace,[_Current|Mfas]}} = (catch erlang:error(get_stacktrace)),erlang:raise(error, conv_reason(Func, Reason), [{io, Func, [Io | Args]}|Mfas]); Other -> Other end. request(Request) -> request(default_output(), Request). request(standard_io, Request) -> request(group_leader(), Request);request(Pid, Request) when is_pid(Pid) -> %%看这里 我们走进的是这个分支 execute_request(Pid, io_request(Pid, Request)); %%io_request/2方法是一个消息格式转换的方法 它的实现摘录在后面request(Name, Request) when is_atom(Name) -> case whereis(Name) of undefined -> {error, arguments}; Pid -> request(Pid, Request) end. execute_request(Pid, {Convert,Converted}) -> %%然后是到了这里 Mref = erlang:monitor(process, Pid), Pid ! {io_request,self(),Pid,Converted}, %%这里向group_leader 发送一个消息,我们看看user进程接收到这个消息之后做了什么 if Convert -> convert_binaries(wait_io_mon_reply(Pid, Mref)); true -> wait_io_mon_reply(Pid, Mref) end.
%%代码路径\erl5.9\lib\kernel-2.15\src\user.erl server_loop(Port, Q) -> receive {io_request,From,ReplyAs,Request} when is_pid(From) -> server_loop(Port, do_io_request(Request, From, ReplyAs, Port, Q)); {Port,{data,Bytes}} -> case get(shell) of noshell -> server_loop(Port, queue:snoc(Q, Bytes)); _ -> case contains_ctrl_g_or_ctrl_c(Bytes) of false -> server_loop(Port, queue:snoc(Q, Bytes)); _ -> throw(new_shell) end end; {Port, eof} -> put(eof, true), server_loop(Port, Q); %% Ignore messages from port here. {'EXIT',Port,badsig} -> % Ignore badsig errors server_loop(Port, Q); {'EXIT',Port,What} -> % Port has exited exit(What); %% Check if shell has exited {'EXIT',SomePid,What} -> case get(shell) of noshell -> server_loop(Port, Q); % Ignore _ -> throw({unknown_exit,{SomePid,What},Q}) end; _Other -> % Ignore other messages server_loop(Port, Q) end.
Eshell V5.9 (abort with ^G)1> whereis(user). <0.23.0>2> erlang:process_info(whereis(user)). [{registered_name,user}, {current_function,{user,server_loop,2}}, {initial_call,{erlang,apply,2}}, {status,waiting}, {message_queue_len,0}, {messages,[]}, {links,[<0.21.0>,<0.24.0>,#Port<0.319>,<0.5.0>]}, {dictionary,[{unicode,false}, {read_mode,list}, {shell,<0.24.0>}]}, {trap_exit,true}, {error_handler,error_handler}, {priority,normal}, {group_leader,<0.23.0>}, {total_heap_size,987}, {heap_size,610}, {stack_size,9}, {reductions,666}, {garbage_collection,[{min_bin_vheap_size,46368}, {min_heap_size,233}, {fullsweep_after,65535}, {minor_gcs,5}]}, {suspending,[]}]3> exit(pid(0,24,0),kill). *** ERROR: Shell process terminated! *** Eshell V5.9 (abort with ^G)1> whereis(user). <0.23.0>2> erlang:process_info(whereis(user)). [{registered_name,user}, {current_function,{user,server_loop,2}}, {initial_call,{erlang,apply,2}}, {status,waiting}, {message_queue_len,0}, {messages,[]}, {links,[<0.5.0>,<0.21.0>,<0.34.0>,#Port<0.319>]}, {dictionary,[{unicode,false}, {read_mode,list}, {shell,<0.34.0>}]}, {trap_exit,true}, {error_handler,error_handler}, {priority,normal}, {group_leader,<0.23.0>}, {total_heap_size,1364}, {heap_size,987}, {stack_size,9}, {reductions,1659}, {garbage_collection,[{min_bin_vheap_size,46368}, {min_heap_size,233}, {fullsweep_after,65535}, {minor_gcs,8}]}, {suspending,[]}]3>
Eshell V5.9 (abort with ^G)1> U =whereis(user). <0.23.0>2> U!{io_request,self(),self(), {put_chars,unicode,io_lib,format, ["hello world :~p~n",[zen]]}}. hello world :zen {io_request,<0.30.0>,<0.30.0>, {put_chars,unicode,io_lib,format, ["hello world :~p~n",[zen]]}}3>
通过修改group_leader,达到io重定向的目的.比如代码:
cat test.erl-module(test). -compile([export_all]). r() ->io:format("group leader:~p~n", [erlang:group_leader()]),io:format("node:~p~n", [node()]),erlang:group_leader(whereis(user), self()),io:format("hello world~n").随后:
erl -sname t1
erl -sname t2
在t1中执行:net_kernel:connect_node('t2@litao').rpc:call('t2@litao', test, r, []).会看到t2中输出hello world
完整协议请点击:http://erlang.org/doc/apps/stdlib/io_protocol.html
io 模块 online documentation
[Erlang 0041] 详解io:format相关推荐
- 非阻塞网络编程详解------IO模型
1.前言 随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力.本文(和下篇<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>)旨在为大家提供有用的 ...
- 详解IO多路复用机制——select、poll、epoll的原理和区别
- Delphi Format函数功能及用法详解
DELPHI中Format函数功能及用法详解 DELPHI中Format函数功能及用法详解function Format(const Format: string; const Args: array ...
- python当中时间模块详解,包括time,timeit,datatime
目录 time 模块 -- 时间获取和转换 以下三个比较常见: time.perf_counter() time.process_time() time.sleep(secs) timeit 模块详解 ...
- 不同格式的图像详解_不同类型的图像格式
不同格式的图像详解 Image Format basically describes how data related to the image will be stored or we can sa ...
- 02Python学习str详解
一.str特点 str为有序字符集,可以切片,可以索引.但是str一旦创建,就无法修改. 二.str内置方法及函数 2.1 str对象.count(子序列,起始位置-可选,结束位置-可选) 字符串 ...
- 【Java网络编程与IO流】Java之Java Servlet详解
Java网络编程与IO流目录: [Java网络编程与IO流]Java中IO流分为几种?字符流.字节流.缓冲流.输入流.输出流.节点流.处理流 [Java网络编程与IO流]计算机网络常见面试题高频核心考 ...
- java io流详解_一文带你看懂JAVA IO流,史上最全面的IO教学啦
一.IO流是什么 惯例引用百科的回答流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操作 ...
- 【测试】linux FIO命令详解(一):磁盘IO测试工具 fio (并简要介绍iostat工具)
目录 随看随用 FIO介绍 FIO 工具常用参数: fio工作参数可以写入配置文件 IO状态监控: Iostat介绍 与FIO相似的工具 fio测试脚本 提取iops和bw gunplot画图 Fio ...
- Fio工具详解【强大的IO性能压测工具】
文章目录 Fio压测工具操作 常用参数 [time] [I/O tpye] [Blocks size] [Job description] [Threads, processes and job sy ...
最新文章
- 服务治理治什么,10张图告诉你答案
- ffmpeg编译 c++ 常量中有换行符
- 兴义智力象机器人_兴义向阳路小学在第十八届全国青少年机器人竞赛贵州区选拔赛夺冠...
- python中如何调用类_python如何调用java类
- 信用卡申请被拒原因分析
- nginx 电子书_Nginx最详细的反向代理配置步骤,拿去不谢
- c盘清理代码_IntelliJ IDEA 缓存和索引介绍和清理方法(一)
- 巴洛克式和哥特式的区别
- three.js黑洞穿越动画js特效
- BiTree T 和 Bitree T 和 BitNode *T 和 T-lchild
- 图片加载防闪动的CSS方法
- 让你的系统无懈可击 史上优秀防火墙一览
- 老男孩上海校区Python面试题
- 软件定义网络实验之SDN网络简单管理及开发
- 打补丁是什么意思?如何快速对云主机批量打补丁?用什么软件?
- 中美知识产权博弈:保护力度标准成最大分歧
- 最优理论与技术--多目标规划问题
- 计算机开机显示器不亮,电脑显示屏不亮但是主机已开机怎么办 电脑显示屏不亮解决方法【图文】...
- 【华东师范大学自然科学版】一种面向双中台双链架构的内生性 数据安全交互协议研究——CSCD
- android 手机系统占用存储,5分钟读懂手机系统文件清理,64G内存也能当作256G使用...
热门文章
- 88相似标准形09——JJordan-Chevalley分解、幂零矩阵与幂零变换、幂零矩阵的判别、中国剩余定理、可换线性变换的性质
- Python生成器中的send()与next()方法解析
- Python入门之类与面向对象(一)
- 无重复元素的组合算法/n个列表中取n个不同的数
- 深度学习:卷积神经网络CNN变体
- 推荐系统:参数协同过滤
- Spatial-Channel Sequeeze Excitation (SCSE)-8-June-2018【论文理解】
- oracle搭建dblink,oracle创建dblink方法示例
- 树莓派 wiringpi 读取引脚_树莓派DHT11温湿度传感器 Python应用实例
- linux下查看pck设备,Linux中查看硬件信息超强命令sar