1

失われた erlang のメッセージに問題があります。

私が使用しているコードは、手動で使用すると 100% 正しく動作しますが、多くの要求と並行してコードをテストする「負荷テスト」でコードが使用された場合にのみ、一部のメッセージが受信側で受信されません。 . すべてのステップとパラメーターの値をログに記録すると、メッセージの送信先アドレスが正しいことがわかりました。メッセージ自体も問題ありません。

私の質問は次のとおりです: erlang でこの「メッセージの損失」についての知識はまだありますか? これは erlang 自体のバグでしょうか?

必要に応じて使用しているコードを投稿することもできますが、特にこの質問に多くの価値が追加されるとは思いません。

更新: 私のアプリケーションの主要部分。これは私の問題を説明するための非常に多くのコードですが、単純化されたバージョンで問題を再現することはできません。アプリケーションは割り当てシステムです。つまり、グリッド内のセルのコレクションを並行して予約します。重要な部分は、割り当てシステム全体を制御するアクターである globalManager です。rowManager はグリッド全体の 1 つの行を管理し、予約が行われるとその行をロックします。セルの領域を予約する必要がある場合、関数 request_specific_cells が呼び出されます。この関数は、行を変更する必要があるすべての行マネージャーに予約要求を送信します。行マネージャーがその行でリージョンを予約すると、globalManager に確認が送信されます。すべてのrowmanagerが確認を送信したら、

    globalManager(Grid) ->
    receive
        {Pid, request_specific_cells, ReservationId, Coordinates, Ctr, XX} ->
            NewGrid = request_specific_cells(Grid, Pid, ReservationId, Coordinates, Ctr, XX);

        {Pid, confirm_region, ResId, Rid, Sid, Region, Section, Ctr, XX} ->
            NewGrid = confirm_region(Grid, Pid, ResId, Rid, Sid, Region, Section, Ctr, XX);

        {Pid, failed_region, Rid, Region, Ctr, XX} ->
            NewGrid = failed_region(Grid, Pid, Rid, Region, Ctr, XX);

        Else ->
            erlang:display({unexpectedMessage, actor, Else}),
            NewGrid = Grid
    end,
    globalManager(NewGrid).


request_specific_cells(Grid, Pid, ReservationId, Coordinates, Ctr, XX) ->
    {{Width, Height}, GridRows, MaxAllocationSize, FreeCells, {UnspecificRequests, NextId}, PendingRequests, BlockedRows} = Grid,
    {X, Y, W, H} = Coordinates,
    Rows         = lists:seq(Y,Y+H-1),
    % Is one of the blocks that have to be reserved currently blocked?
    BlockedRow   = lists:foldl(fun(B, Acc) -> Acc xor search_list(B,BlockedRows) end, false, Rows),
    Request      = lists:keyfind(ReservationId, 1, UnspecificRequests),
    {ReservationId, _} = Request,
    % Now we need the addresses of the sections in which the regions has to be reserved.
    SubSectionIds = [ SPid || {_,SPid} <- [ lists:keyfind(Row, 1, GridRows) || Row <- Rows]],
    % Storing request enables us to rollback if one of the registrations fails.
    NewPendingRequests = PendingRequests ++ [{length(PendingRequests), 0, lists:map(fun(S) -> {S,null} end, SubSectionIds)}],
    % Send a registration command with the needed section to each corresponding section manager.
    [SPid ! {self(), request, Pid, ReservationId, length(PendingRequests), Coordinates, Ctr, XX} || SPid<- SubSectionIds],
    NewBlockedRows = Rows ++ BlockedRows,
    {{Width, Height}, GridRows, MaxAllocationSize, FreeCells, {UnspecificRequests, NextId}, NewPendingRequests, NewBlockedRows}
    end.


confirm_region(Grid, Pid, URid, Rid, Sid, Region, Section, Cttr, XX) ->
    {Dimensions, GridRows, MaxAllocationSize, FreeCells, {UnspecificRequests, NextId}, PendingRequests, BlockedRows} = Grid,
    {_,RY,_,_} = Region,
    if
        % All blocks have confirmed the reservation so the entire request is successful
        (Ctr+1) == length(Spids) -> 
                NewUnspecificRequests = lists:keydelete(URid, 1, UnspecificRequests),
                NewPendingRequests = lists:keydelete(Rid, 1, PendingRequests),
                NewSpids = lists:keyreplace(Sid, 1, Spids, {Sid, Section}),
                [Spid ! {self(), confirm_region, Sec} || {Spid, Sec} <- NewSpids],
                Pid ! {self(), request_specific_cells, Rid, success};
        true -> 
                NewUnspecificRequests = UnspecificRequests,
                % Safe the region that has to be marked/rolled back in the row
                NewSpids = lists:keyreplace(Sid, 1, Spids, {Sid, Section}),
                % Increase counter of confirmations
                NewPendingRequests = lists:keyreplace(Rid, 1, PendingRequests, {Rid, Ctr+1, NewSpids})
    end,
    NewBlockedRows = delete_list(RY, BlockedRows)
    {Dimensions, GridRows, MaxAllocationSize, FreeCells, {NewUnspecificRequests, NextId}, NewPendingRequests, NewBlockedRows}.



rowManager(Row) ->
    receive
        {Mid, request, Pid, URid, Rid, Region, Ctr, XX} ->
            NewRow = request_region(Row, Mid, Pid, URid, Rid, Region, Ctr, XX);
        Else ->
            erlang:display({unexpectedMessage, rowManager, Else}),
            NewRow = Row
    end,

    rowManager(NewRow).

request_region(Row, Mid, Pid, URid, Rid, Coordinates, Ctr, XX) ->
    {RY, Content, Modified} = Row,
    {X,_,W,_}    = Coordinates,
    if
        Modified == false -> 
                Free = region_is_empty({X,1,W,1}, Content),
                if
                    Free -> NewModified = true,
                            NewContent = mark_region({X,1,W,1}, Content, reserved),
                            Mid ! {Pid, confirm_region, URid, Rid, self(), Coordinates, {X,1,W,1}, Ctr, XX};
                    true -> NewModified = false,
                            NewContent = Content,
                            Mid ! {Pid, failed_region, Rid, Coordinates, Ctr, XX}
                end;
        true -> NewModified = false,
                NewContent = Content,
                Mid ! {Pid, failed_region, Rid, Coordinates, Ctr, XX}
    end,
    {RY, NewContent, NewModified}. 

このコードはリザーバーによって使用されます。

request_specific_cells(FollowUpPid, ReservationId, {X, Y, Width, Height}, Ctr, XX) ->
   FollowUpPid ! {self(), request_specific_cells, ReservationId, {X, Y, Width, Height}, Ctr, XX},
   receive
      {FollowUpPid, request_specific_cells, ReservationId, SuccessOrFailure} ->
        SuccessOrFailure
end.

私はそれを知っているので、この受信機は応答が受信される前に死ぬと思います

Pid ! {self(), request_specific_cells, Rid, success}

confirm/9 関数からの値は常に正しい値で実行されますが、常に関数で受信されるとは限りません。

4

1 に答える 1

3

Erlang は、受信者が生きている場合、同じノード内で強力なメッセージ配信を保証します。

コードに競合状態があるようです。同じ問題を抱えているアプリケーションの小さな例を書いて、ここに投稿してみてください。

于 2013-04-18T13:24:51.770 に答える