这是一个示例流程,可以选择三个特定的初始扑克选项:
defmodule PokerTable do
# ...more stuff here - in particular, implementations
# ... of process* and has_bet functions, state initialization
# ... and more irrelevant stuff
defp ask_option_on_no_bet(currentTableState) do
user = currentTableState.currentUser
newTableState = receive do
{ ^user, :bet, amount } -> process_bet(currentTableState, amount)
{ ^user, :check } -> process_check(currentTableState)
{ ^user, :fold } -> process_fold(currentTableState)
after 15000 -> process_check(currentTableState)
end
end
defp ask_option_on_bet(currentTableState) do
user = currentTableState.currentUser
newTableState = receive do
{ ^user, :raise, amount } -> process_raise(currentTableState, amount)
{ ^user, :call } -> process_check(currentTableState)
{ ^user, :fold } -> process_fold(currentTableState)
after 15000 -> process_fold(currentTableState)
end
end
def ask_option(currentTableState) do
if has_bet(currentTableState) do
ask_option_on_no_bet(currentTableState)
else
ask_option_on_bet(currentTableState)
end
end
end
在这种情况下,这个PokerTable只是一个类似于扑克界面的示例模块。那些玩在线扑克网站的人会非常清楚这个界面意味着什么,而且喜欢Elixir的一个理由是开箱即用的能力。
代码的含义是:当新消息到达时,读取内部消息堆栈以查找到达的消息是否与这些子句中的任何一个匹配,并对其进行处理。如果此调用后15秒后未收到匹配的消息,则执行默认操作。
这种方法虽然诱人,但有一点需要注意:不匹配的消息将保留在内部流程中。消息框(这是一个FIFO),这意味着两件事:
然后我可以为receive
块阻止以下方法:
defp ask_option_on_no_bet(currentTableState) do
user = currentTableState.currentUser
newTableState = receive do
{ ^user, :bet, amount } -> process_bet(currentTableState, amount)
{ ^user, :check } -> process_check(currentTableState)
{ ^user, :fold } -> process_fold(currentTableState)
anyJunk ->
tell_the_user_they_sent_junk(user)
ask_option_on_no_bet(currentTableState)
after 15000 -> process_check(currentTableState)
end
end
defp ask_option_on_bet(currentTableState) do
user = currentTableState.currentUser
newTableState = receive do
{ ^user, :raise, amount } -> process_raise(currentTableState, amount)
{ ^user, :call } -> process_check(currentTableState)
{ ^user, :fold } -> process_fold(currentTableState)
anyJunk ->
tell_the_user_they_sent_junk(user)
ask_option_on_bet(currentTableState)
after 15000 -> process_fold(currentTableState)
end
end
现在我避免在邮件队列中存储垃圾。到现在为止还挺好。但是,这会导致对receive
的新来电,重置计时器,因为after
会在当前receive
来电后运行。
我的想法是:
receive
和垃圾命令之间当前经过的毫秒数。15000 - theRetrievedElapsedMiliseconds
并将该值保留为州的成员(在这种情况下我们会更新,并且我们会在ask_option
上初始化为15000)。after 15000
,在remainingTime = currentTableState.remainingTime
块中使用两行after remainingTime
和receive
(并在currentTableState中更新remainingTime
,生成新状态为尾调用。)我的问题是:如何检索自receive
以来经过的时间?
答案 0 :(得分:1)
我会这样做:
向函数添加第二个参数,默认值为15000,即总超时。
当功能启动时,存储当前时间。
当它进入any_junk
分支时,减去剩余时间,然后进行递归调用。
defp ask_option_on_no_bet(currentTableState, remaining \\ 15000) do
start = now()
user = currentTableState.currentUser
newTableState = receive do
{ ^user, :bet, amount } -> ...
{ ^user, :check } -> ...
{ ^user, :fold } -> ...
any_junk ->
elapsed = now() - start
ask_option_on_no_bet(currentTableState, remaining - elapsed)
after remaining ->
process_check(currentTableState)
end
end
now()
只是一个简单的函数,以毫秒为单位返回当前的单调时间:
defp now, do: System.monotonic_time(:millisecond)