了解 Erlang 中的选择性接收
Understanding selective receives in Erlang
我正在阅读有关超时的 LYAE
一章,但我无法理解在以下情况下会发生什么:
important() ->
receive
{Priority, Message} when Priority > 10 ->
[Message | important()]
after 0 ->
normal()
end.
normal() ->
receive
{_, Message} ->
[Message | normal()]
after 0 ->
[]
end.
1> c(multiproc).
{ok,multiproc}
2> self() ! {15, high}, self() ! {7, low}, self() ! {1, low}, self() ! {17, high}.
{17,high}
3> multiproc:important().
[high,high,low,low]
我不明白以下内容:
- 说
after 0
就像使用 ,
据我所知,如果消息在 receive
子句中匹配,它会发生 EVEN?
- 阅读第一条消息后,我们有
[15, important()]
,在第二次迭代时会调用 normal
,所以我们有一只手 [15, important() --3-rd call]
和 [7,normal() -fourth call]
。
那么最终我们如何以某种方式得到两个连接起来的列表。
- 阅读前 2 条消息后,我们得到:
important
与 [15]
normal
(第一次通话)与 [7]
现在 normal()
(第一次呼叫)已经在等待新消息,important
现在将第二次呼叫 normal()
所以现在第二次呼叫不会我们有 [1]
?
我不明白 [7]
和 [1]
是如何合并的,因为它们来自对 normal()
.
的单独调用
我理解 important()
,因为结果放在列表的末尾 [Message,important()]
。但 normal()
的情况并非如此,因为它被 [=19] 调用=] 并且每次它都应该创建一个新列表。
P.S 我添加了一张图片,进一步解释我的 dilemma.I 我想我现在明白了,最后 2 个分支将 return 他们的结果变成 [7,15]
但我还是不明白顺序是什么。
在 receive
中,我们将在其中一个匹配子句或 after
子句中 结束。也就是说,after
子句只有在超时内没有匹配的消息时才会被评估。这与 after
在 try
/catch
中的行为不同,后者将无条件求值。
这两个函数遵循常见的 Erlang 模式:通过递归调用构建列表 - 选择性 receive
在这里并不重要。注意这个表达式:
[Message | important()]
等同于:
[Message] ++ important()
也就是说,我们正在创建一个列表,其第一个元素是我们收到的消息,其尾部由任何递归调用组成 returns。结果是我们得到一个接一个收到的消息列表。事实上,在某些时候我们切换到调用 normal()
而不是 important()
并没有改变这一点 - 我们仍然一次构建列表一个元素。
一步一步:
- 我们从 shell
调用 multiproc:important()
important
收到 {15, high}
,我们现在正在评估 [high] ++ important()
- 对
important
的递归调用忽略了 {7, low}
因为它不匹配,但是接收到 {17, high}
匹配。我们现在正在评估 [high] ++ [high] ++ important()
- 对
important
的第二次递归调用没有看到任何匹配的消息并进入 after
子句。我们现在正在评估 [high] ++ [high] ++ normal()
- 对
normal
的调用收到 {7, low}
,我们现在正在评估 [high] ++ [high] ++ [low] ++ normal()
- 对
normal
的递归调用收到 {1, low}
,我们现在正在评估 [high] ++ [high] ++ [low] ++ [low] ++ normal()
- 对
normal
的第二次递归调用没有看到任何匹配的消息,并且 returns []
没有进行递归调用。我们现在有 [high] ++ [high] ++ [low] ++ [low] ++ []
,等于 [high, high, low, low]
.
Saying after 0 its like using , from what i understand, it happens
EVEN if the message matches in the receive clause?
错了。如果消息匹配,则跳过 after
。
After reading the first message we have [15, important()],
错了。 [15 | important()]
与 [15, important()]
不同。 15 是 Priority
——不是 Message
,但它是 Message
,例如high
,即被插入到列表中。
somehow we end up with two lists that get concatenated.
错了。邮箱中有以下消息:
{15, high}
{7, low}
{1, low}
{17, high}
第一次重要()调用:
{15, high} matches the important() receive
return value: [high | important()]
现在 erlang 需要调用 important() again
并将 return 值替换为 [high | important()]
.
邮箱中有以下邮件:
{7, low}
{1, low}
{17, high}
第二次重要()调用:
{7, low} doesn't match the important() receive
{1, low} doesn't match the important() receive
{17, high} matches the important() receive
return value: [high | important()]
代入第一个重要return值的结果:
[high | important()] -- 2nd important() return value
|
V
[high | important()] -- 1st important() return value
给你:
[high | [high | important()] ]
现在,erlang 必须第三次调用 important()
并将第三次调用的 return 值代入该结果。
邮箱中有以下邮件:
{7, low}
{1, low}
第三次重要()调用:
{7, low} doesn't match the important() receive
{1, low} doesn't match the important() receive
So, the after executes immediately--because the timeout is 0.
return value: normal().
将结果 [high | [high | important()] ]
中的 important() 替换为 normal()
得到:
[high | [high | normal()] ]
现在 erlang 必须评估 normal()
并将其 return 值代入该结果。
第一次正常()调用:
{7, low} matches the normal() receive
return value: [low | normal()]
进行替换:
[low | normal()]
|
V
[high | [high | normal()] ]
给出:
[high | [high | [low | normal()] ] ]
邮箱中有以下邮件:
{1, low}
第二次正常()调用:
{1, low} matches the normal() receive
return value: [low | normal()]
进行替换:
[low | normal()]
|
V
[high | [high | [low | normal()] ] ]
产生:
[high | [high | [low | [low | normal()] ] ] ]
邮箱中有以下邮件:
<none>
第 3 次正常调用:
The after executes immediately because the timeout is 0.
return value: []
替代:
[]
|
V
[high | [high | [low | [low | normal() ] ] ] ]
给出:
[high | [high | [low | [low | [] ] ] ] ].
这是什么乱七八糟的东西??!
7> [high | [high | [low | [low | [] ] ] ] ].
[high,high,low,low]
在 erlang 中,列表是使用 cons 运算符 |
和嵌套子列表递归定义的。以下是一些其他示例:
8> [1 | [2 | [] ]].
[1,2]
|
(cons 运算符)右边的东西必须是一个列表。 Erlang 语法也允许你这样写:
10> [1, 2, 3 | [4, 5]].
[1,2,3,4,5]
再一次,|
运算符右边的东西必须是一个列表,但是你可以在左边写逗号分隔值。
我正在阅读有关超时的 LYAE
一章,但我无法理解在以下情况下会发生什么:
important() ->
receive
{Priority, Message} when Priority > 10 ->
[Message | important()]
after 0 ->
normal()
end.
normal() ->
receive
{_, Message} ->
[Message | normal()]
after 0 ->
[]
end.
1> c(multiproc).
{ok,multiproc}
2> self() ! {15, high}, self() ! {7, low}, self() ! {1, low}, self() ! {17, high}.
{17,high}
3> multiproc:important().
[high,high,low,low]
我不明白以下内容:
- 说
after 0
就像使用,
据我所知,如果消息在receive
子句中匹配,它会发生 EVEN? - 阅读第一条消息后,我们有
[15, important()]
,在第二次迭代时会调用normal
,所以我们有一只手[15, important() --3-rd call]
和[7,normal() -fourth call]
。 那么最终我们如何以某种方式得到两个连接起来的列表。 - 阅读前 2 条消息后,我们得到:
important
与 [15]
normal
(第一次通话)与 [7]
现在 normal()
(第一次呼叫)已经在等待新消息,important
现在将第二次呼叫 normal()
所以现在第二次呼叫不会我们有 [1]
?
我不明白 [7]
和 [1]
是如何合并的,因为它们来自对 normal()
.
我理解 important()
,因为结果放在列表的末尾 [Message,important()]
。但 normal()
的情况并非如此,因为它被 [=19] 调用=] 并且每次它都应该创建一个新列表。
P.S 我添加了一张图片,进一步解释我的 dilemma.I 我想我现在明白了,最后 2 个分支将 return 他们的结果变成 [7,15]
但我还是不明白顺序是什么。
在 receive
中,我们将在其中一个匹配子句或 after
子句中 结束。也就是说,after
子句只有在超时内没有匹配的消息时才会被评估。这与 after
在 try
/catch
中的行为不同,后者将无条件求值。
这两个函数遵循常见的 Erlang 模式:通过递归调用构建列表 - 选择性 receive
在这里并不重要。注意这个表达式:
[Message | important()]
等同于:
[Message] ++ important()
也就是说,我们正在创建一个列表,其第一个元素是我们收到的消息,其尾部由任何递归调用组成 returns。结果是我们得到一个接一个收到的消息列表。事实上,在某些时候我们切换到调用 normal()
而不是 important()
并没有改变这一点 - 我们仍然一次构建列表一个元素。
一步一步:
- 我们从 shell 调用
important
收到{15, high}
,我们现在正在评估[high] ++ important()
- 对
important
的递归调用忽略了{7, low}
因为它不匹配,但是接收到{17, high}
匹配。我们现在正在评估[high] ++ [high] ++ important()
- 对
important
的第二次递归调用没有看到任何匹配的消息并进入after
子句。我们现在正在评估[high] ++ [high] ++ normal()
- 对
normal
的调用收到{7, low}
,我们现在正在评估[high] ++ [high] ++ [low] ++ normal()
- 对
normal
的递归调用收到{1, low}
,我们现在正在评估[high] ++ [high] ++ [low] ++ [low] ++ normal()
- 对
normal
的第二次递归调用没有看到任何匹配的消息,并且 returns[]
没有进行递归调用。我们现在有[high] ++ [high] ++ [low] ++ [low] ++ []
,等于[high, high, low, low]
.
multiproc:important()
Saying after 0 its like using , from what i understand, it happens EVEN if the message matches in the receive clause?
错了。如果消息匹配,则跳过 after
。
After reading the first message we have [15, important()],
错了。 [15 | important()]
与 [15, important()]
不同。 15 是 Priority
——不是 Message
,但它是 Message
,例如high
,即被插入到列表中。
somehow we end up with two lists that get concatenated.
错了。邮箱中有以下消息:
{15, high}
{7, low}
{1, low}
{17, high}
第一次重要()调用:
{15, high} matches the important() receive
return value: [high | important()]
现在 erlang 需要调用 important() again
并将 return 值替换为 [high | important()]
.
邮箱中有以下邮件:
{7, low}
{1, low}
{17, high}
第二次重要()调用:
{7, low} doesn't match the important() receive
{1, low} doesn't match the important() receive
{17, high} matches the important() receive
return value: [high | important()]
代入第一个重要return值的结果:
[high | important()] -- 2nd important() return value
|
V
[high | important()] -- 1st important() return value
给你:
[high | [high | important()] ]
现在,erlang 必须第三次调用 important()
并将第三次调用的 return 值代入该结果。
邮箱中有以下邮件:
{7, low}
{1, low}
第三次重要()调用:
{7, low} doesn't match the important() receive
{1, low} doesn't match the important() receive
So, the after executes immediately--because the timeout is 0.
return value: normal().
将结果 [high | [high | important()] ]
中的 important() 替换为 normal()
得到:
[high | [high | normal()] ]
现在 erlang 必须评估 normal()
并将其 return 值代入该结果。
第一次正常()调用:
{7, low} matches the normal() receive
return value: [low | normal()]
进行替换:
[low | normal()]
|
V
[high | [high | normal()] ]
给出:
[high | [high | [low | normal()] ] ]
邮箱中有以下邮件:
{1, low}
第二次正常()调用:
{1, low} matches the normal() receive
return value: [low | normal()]
进行替换:
[low | normal()]
|
V
[high | [high | [low | normal()] ] ]
产生:
[high | [high | [low | [low | normal()] ] ] ]
邮箱中有以下邮件:
<none>
第 3 次正常调用:
The after executes immediately because the timeout is 0.
return value: []
替代:
[]
|
V
[high | [high | [low | [low | normal() ] ] ] ]
给出:
[high | [high | [low | [low | [] ] ] ] ].
这是什么乱七八糟的东西??!
7> [high | [high | [low | [low | [] ] ] ] ].
[high,high,low,low]
在 erlang 中,列表是使用 cons 运算符 |
和嵌套子列表递归定义的。以下是一些其他示例:
8> [1 | [2 | [] ]].
[1,2]
|
(cons 运算符)右边的东西必须是一个列表。 Erlang 语法也允许你这样写:
10> [1, 2, 3 | [4, 5]].
[1,2,3,4,5]
再一次,|
运算符右边的东西必须是一个列表,但是你可以在左边写逗号分隔值。