Erlang生产者和消费者 - 程序的奇怪行为

时间:2018-01-06 21:48:46

标签: erlang multiprocessing producer-consumer

我正在编写一个程序,使用Erlang多处理解决生产者 - 消费者问题,其中一个流程负责处理我生产/消费的缓冲区以及许多生产者和许多消费者流程。为了简化,我假设生产者/消费者不知道他的操作已经失败(由于缓冲区约束而无法生成或使用),但服务器已准备好这样做。

我的代码是:

服务器代码

server(Buffer, Capacity, CountPid) ->
  receive
%%    PRODUCER
    {Pid, produce, InputList} ->
      NumberProduce = lists:flatlength(InputList),
      case canProduce(Buffer, NumberProduce, Capacity) of
        true ->
          NewBuffer = append(InputList, Buffer),
          CountPid ! lists:flatlength(InputList),
          Pid ! ok,
          server(NewBuffer,Capacity, CountPid);
        false ->
          Pid ! tryagain,
          server(Buffer, Capacity, CountPid)
      end;

%%    CONSUMER
    {Pid, consume, Number} ->
      case canConsume(Buffer, Number) of
        true ->
          Data = lists:sublist(Buffer, Number),
          NewBuffer = lists:subtract(Buffer, Data),
          Pid ! {ok, Data},
          server(NewBuffer, Capacity,CountPid);
        false ->
          Pid ! tryagain,
          server(Buffer, Capacity, CountPid)

      end
  end.

制作人和消费者

producer(ServerPid) ->
  X = rand:uniform(9),
  ToProduce = [rand:uniform(500) || _ <- lists:seq(1, X)],
  ServerPid ! {self(),produce,ToProduce},

  producer(ServerPid).

consumer(ServerPid) ->
  X = rand:uniform(9),
  ServerPid ! {self(),consume,X},

  consumer(ServerPid).

启动和辅助功能(我附上,因为我不知道我的问题究竟在哪里)

spawnProducers(Number, ServerPid) ->
  case Number of
    0 -> io:format("Spawned producers");
    N ->
      spawn(zad2,producer,[ServerPid]),
      spawnProducers(N - 1,ServerPid)
  end.

spawnConsumers(Number, ServerPid) ->
  case Number of
    0 -> io:format("Spawned producers");
    N ->
      spawn(zad2,consumer,[ServerPid]),
      spawnProducers(N - 1,ServerPid)
  end.

start(ProdsNumber, ConsNumber) ->
  CountPid = spawn(zad2, count, [0,0]),

  ServerPid = spawn(zad2,server,[[],20, CountPid]),

  spawnProducers(ProdsNumber, ServerPid),
  spawnConsumers(ConsNumber, ServerPid).

canProduce(Buffer, Number, Capacity) ->
  lists:flatlength(Buffer) + Number =< Capacity.

canConsume(Buffer, Number) ->
  lists:flatlength(Buffer) >= Number.


append([H|T], Tail) ->
  [H|append(T, Tail)];
append([], Tail) ->
  Tail.

我正在尝试使用这样的进程计算元素数量,服务器会在生成元素时向其发送消息。

count(N, ThousandsCounter) ->
  receive
    X ->
      if
        N >= 1000 ->
          io:format("Yeah! We have produced ~p elements!~n", [ThousandsCounter]),
          count(0, ThousandsCounter + 1000);
        true -> count(N + X, ThousandsCounter)
      end
  end.

我希望这个程序能够正常工作,这意味着:它产生元素,生成元素的增加取决于时间,如f(t)= kt,k-constant和我生产的生产速度越快的过程。

实际问题
我启动了程序:

  1. erl
  2. c(zad2)
  3. zad2:start(5,5)
  4. 程序的行为:

    1. 生产时间越长,生产时间单位中的元素越少(例如,在第一秒10000,在接下来的5000,在第10秒1000等。
    2. 我拥有的流程越多,生产越慢,在开始时(10,10)我需要等待大约一秒钟的第一千,而对于开始(2,2)20000几乎立即出现
    3. start(100,100)让我重新启动计算机(我在Ubuntu上工作),因为整个CPU都被使用了,没有内存供我打开终端并终止erlang机器
    4. 为什么我的程序行为不像我期望的那样?我在使用Erlang编程时遇到了什么问题,还是操作系统或其他任何问题?

1 个答案:

答案 0 :(得分:0)

上面写的producer / 1和consumer / 1函数不会等待任何事情 - 它们只是循环和循环,用消息轰炸服务器。服务器的消息队列正在快速填满,Erlang VM将尽可能地增长,窃取所有内存,循环进程将窃取所有内核的所有可用CPU时间。