Elixir 处理或防止的惯用方法;竞赛条件“;灵丹妙药

Elixir 处理或防止的惯用方法;竞赛条件“;灵丹妙药,elixir,phoenix-framework,Elixir,Phoenix Framework,对不起,这个愚蠢的问题。但我是一个新手在长生不老药来自戈朗 我真的很喜欢elixir和FP风格,我尝试实现一些基本功能,但在websocket连接上遇到了种族条件问题。例如,在golang中,我使用互斥来解决它,但它不是FP样式 初始问题: 多个WebSocket连接,等待5人组。然后随机洗牌。在这个例子中,我遇到了一些关于“比赛条件”的问题。同一个人分为不同的群体等 用长生不老药解决这个问题的惯用方法是什么 谢谢你的帮助。再一次为一个愚蠢的问题感到抱歉 我将分享我丑陋的代码片段) 例如,两个并

对不起,这个愚蠢的问题。但我是一个新手在长生不老药来自戈朗

我真的很喜欢elixir和FP风格,我尝试实现一些基本功能,但在websocket连接上遇到了种族条件问题。例如,在golang中,我使用互斥来解决它,但它不是FP样式

初始问题: 多个WebSocket连接,等待5人组。然后随机洗牌。在这个例子中,我遇到了一些关于“比赛条件”的问题。同一个人分为不同的群体等

用长生不老药解决这个问题的惯用方法是什么

谢谢你的帮助。再一次为一个愚蠢的问题感到抱歉

我将分享我丑陋的代码片段)

例如,两个并发用户通过状态加入了Lobble channel I track。之后,当一些用户发送“匹配”事件时,我会在大厅中找到其他在线用户,直到有多个

defp match(user_id, online_list) when length(online_list) < 1
defp匹配(用户标识,在线列表)长度(在线列表)<1时
然后我创建一个房间并将房间id发送给他们。但当两个用户发送一个匹配时,我有两个房间,因为比赛条件

我想为一组用户提供一个公共休息室。在这种情况下,我可以使用互斥和共享。但我不知道如何在长生不老药中实现这种逻辑

现在如果Alice调用该事件,我有足够的用户支持Alice,但是Bob同时调用该事件,他也有足够的用户。但他们需要在一个共同的群体中,而不是在两个独立的群体中。它们相交

def match(user_id) do
    user_id = Integer.to_string(user_id)
    match(user_id, [])
  end

  defp match(user_id, online_list) when length(online_list) < 1 do
    new_online_list =
      RchatWeb.Presence.list("room:lobby")
      |> Map.delete(user_id)
      |> Map.keys()
    match(user_id, new_online_list)
  end

  defp match(first_user_id, online_list) do
    second_user_id = Enum.random(online_list) |> String.to_integer()
    second_room_id = Accounts.get_user_room_id(second_user_id)
    {:ok, room} = cond do
      is_nil(second_room_id) -> create_room()
      true -> {:ok, get_room!(second_room_id)}
    end
    # Try to fix race condition with presence or channels
    {:ok, first_user} =
      Accounts.get_user!(first_user_id)
      |> Accounts.update_user(%{room_id: room.id})
    {:ok, second_user} =
      Accounts.get_user!(second_user_id)
      |> Accounts.update_user(%{room_id: room.id})
    ids = [first_user.id, second_user.id]
    {:ok, room.hash, ids}
  end
def匹配(用户id)是否执行
user\u id=Integer.to\u字符串(user\u id)
匹配(用户id,[])
结束
当长度(在线列表)小于1 do时,defp匹配(用户id,在线列表)
新的在线列表=
RchatWeb.Presence.list(“房间:大厅”)
|>Map.delete(用户id)
|>Map.keys()
匹配(用户id、新联机列表)
结束
defp匹配(第一个用户id,在线列表)do
second_user_id=Enum.random(在线_列表)|>String.to_integer()
second\u room\u id=帐户。获取用户\u room\u id(second\u user\u id)
{:好的,房间}=cond do
is_nil(第二个房间id)->创建房间()
正确->{:好的,去房间!(第二个房间id)}
结束
#尝试使用状态或通道修复争用条件
{:好的,第一个用户}=
Accounts.get\u用户!(第一个用户id)
|>Accounts.update_user(%{room_id:room.id})
{:好的,第二个用户}=
Accounts.get\u用户!(第二个用户id)
|>Accounts.update_user(%{room_id:room.id})
ids=[第一个用户id,第二个用户id]
{:好的,room.hash,ids}
结束

Elixir没有可变状态,因此本地互斥的概念在那里毫无意义。分布式锁可以有一些用例,但这与本地互斥锁非常不同

请记住,每个过程都是连续的,因此,如果我正确理解您的用例,您会希望:

defmodulequeue do
使用GenServer
def start_link(uu),do:GenServer.start_link(uu模块,[])
def寄存器_和_等待(pid),
do:GenServer.call(pid,{:register,self()},:无穷大)
def init(551;),do:{:好的,[]}
def handle_调用({:register,pid},from,participants)do
新的|状态=[{pid,来自}|参与者]
箱长(新_状态)do
5 ->
shuffled=Enum.shuffle(新状态)
{pids,refs}=Enum.unzip(无序)
参考
{:回复,{:等等,5-n},新州}
_ ->
{:答复::拥挤不堪,与会者}
结束
结束
结束

现在,
register_和_wait/1
将注册当前进程,并根据需要锁定(注意无限锁定)尽可能多的进程(在本例中为5个,但可以进行配置)。只要有足够多的进程需要注册,就不可能出现死锁,然后返回
{:ready,shuffled\u list\u of_pids}

Elixir没有可变状态,因此本地互斥体的概念在那里毫无意义。分布式锁可以有一些用例,但这与本地互斥锁非常不同

请记住,每个过程都是连续的,因此,如果我正确理解您的用例,您会希望:

defmodulequeue do
使用GenServer
def start_link(uu),do:GenServer.start_link(uu模块,[])
def寄存器_和_等待(pid),
do:GenServer.call(pid,{:register,self()},:无穷大)
def init(551;),do:{:好的,[]}
def handle_调用({:register,pid},from,participants)do
新的|状态=[{pid,来自}|参与者]
箱长(新_状态)do
5 ->
shuffled=Enum.shuffle(新状态)
{pids,refs}=Enum.unzip(无序)
参考
{:回复,{:等等,5-n},新州}
_ ->
{:答复::拥挤不堪,与会者}
结束
结束
结束

现在,
register_和_wait/1
将注册当前进程,并根据需要锁定(注意无限锁定)尽可能多的进程(在本例中为5个,但可以进行配置)。只要有足够多的进程需要注册,就不可能出现死锁,然后将返回
{:ready,shuffled_list_of_pids}

请显示代码,从您的描述中很难理解问题所在。++code snippet请显示代码,从您的描述中很难理解问题所在。++代码片段谢谢,我共享了我的代码片段以更好地描述初始问题。谢谢,我共享了我的代码片段以更好地描述初始问题。