我一直在Erlang为学校项目制作聊天应用程序,但我遇到了一个问题。我正在尝试使我的程序并发,为了这样做,我为每个通道发送的消息启动一个新线程。我这样做是使用列表:foreach,但我想确保我不会给输入频道的人留言。
request(State, {message, {UserID,UserPID}, Token}) ->
case catch lists:member({UserID,UserPID}, State#channel.users) of
false ->
{{error, user_not_joined}, State};
true ->
spawn( fun() ->
ListOfUsers = State#channel.users,
UserPIDs = lists:map(fun ({_, V}) -> V end, ListOfUsers),
%spawn( fun() ->end)
lists:foreach(
fun(UserPID) -> ok end,
fun(PID) ->
spawn( fun() -> genserver:request(PID, {message_from_server, State#channel.name, UserID, Token}) end)
end, UserPIDs) end),
{ok, State}
end;
我最想做的是匹配foreach中的UserPID。截至目前,我只收到警告:
channel.erl:39:警告:变量'UserPID'未使用 channel.erl:39:警告:变量'UserPID'在'fun'中隐藏
第3行很有趣(UserPID) - >好的结束,
干杯
答案 0 :(得分:5)
legoscia的答案很好,但我补充一点,列表理解通常比lists:foreach
更易于使用且阅读更简单。请注意,列表推导能够忽略基于子句的值。请考虑以下示例:
-module(filter).
-export([do/0]).
do() ->
Values = lists:seq(1,10),
IgnoreThisValue = 5,
%% print all values unequal to IgnoreThisValue
[io:format("Value: ~b~n", [Value]) ||
Value <- Values, Value =/= IgnoreThisValue],
ok.
在shell中运行它:
1> make:all([load]).
Recompile: filter
up_to_date
2> filter:do().
Value: 1
Value: 2
Value: 3
Value: 4
Value: 6
Value: 7
Value: 8
Value: 9
Value: 10
关于代码的旁注:为什么每个进程都会产生一个线程?我假设您正在使用行为gen_server
(如果我错了,请纠正我)。如果是这样,您应该考虑使用cast
函数来发送消息。由于您没有检查genserver:request/2
的结果,这可能是一个可行的选项,可以为您节省大量的流程。
答案 1 :(得分:3)
由于函数参数会影响现有变量,因此需要使用保护:
fun(PID) when PID =:= UserPID -> ok end