【问题标题】:Concurrent Sieve in ErlangErlang 中的并发筛选器
【发布时间】:2018-08-10 04:54:19
【问题描述】:

我有一个代码,它使用 Eratosthenes 筛法来生成最高给定限制 N 的素数。

方法:

  1. 将奇数列表拆分成段
  2. 每个段都被传递给一个进程
  3. Segments 与集合 Lp 同时筛选

代码如下:

%---------------------------------------------------------------------------------   
primes(N) ->
    simple_sieve(lists:seq(3,N,2),[],N).

    simple_sieve(Lin,Lp,N) -> [H|_] = Lin,
        case H*H < N of
               true -> simple_sieve([X || X <- Lin, X rem H =/= 0], [H|Lp], N);
               false -> lists:reverse(Lp) ++ Lin
        end.

%---------------------------------------------------------------------------------
primes_parr(N, Num_blocks) -> 
    Pid_stem = self(),
    SQ = round(math:sqrt(N)),
    Lp = primes(SQ), io:fwrite("List of primes: ~w~n", [Lp]),
    Block_size = round(N/Num_blocks),
    ok = leaf_spawn(Pid_stem, Lp, SQ, Block_size, Num_blocks),  
    stem_loop(Lp, 0, Num_blocks).

stem_loop(Lp, Primes, 0) ->
    1 + length(Lp) + Primes;
stem_loop(Lp, Primes, Num_blocks) ->
    receive
    {leaf_done, _, Leaf_nums} ->
        stem_loop(Lp, Primes+Leaf_nums, Num_blocks-1)
    end.

leaf_spawn(_, _, _, _, 0) -> ok;
leaf_spawn(Pid_stem, Lp, SQ, Block_size, Num_blocks) ->
    case (Num_blocks==1) of
    true -> case (SQ rem 2 == 0) of
            true -> Start = SQ+1;
            false -> Start = SQ
        end;
    false -> Start = 1
    end,
    First = (Num_blocks-1)*Block_size + Start, 
    Last = Num_blocks*Block_size,
    io:fwrite("Start: ~w | Finish: ~w ~n", [First,Last]),   
    spawn(fun() -> leaf(Pid_stem, Num_blocks, First, Last, [], Lp) end), 
    leaf_spawn(Pid_stem, Lp, SQ, Block_size, Num_blocks-1).

leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, []) -> 
    L = ordsets:subtract(lists:seq(First,Last,2),lists:usort(Leaf_nums)), 
    io:fwrite("The sublist is: ~w~n", [L]),
    Pid_stem ! {leaf_done, Leaf_id, length(ordsets:subtract(lists:seq(First,Last,2),lists:usort(Leaf_nums)))};
leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, [H|T]) ->
    case (H*H =< Last)  of
    true -> 
        case H*H >= First of
        true ->
            leaf(Pid_stem, Leaf_id, First, Last, lists:seq(H*H, Last, 2*H) ++ Leaf_nums, T);
        false ->
            K = round((First - H*H)/(2*H)),
            leaf(Pid_stem, Leaf_id, First, Last, lists:seq(H*H + 2*K*H, Last, 2*H) ++ Leaf_nums, T)
        end;
    false -> 
        leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, [])
    end.

如果我调用函数 primes_parr(100,2),代码就可以正常工作。给我输出:

List of primes(Lp): [3,5,7]
Start: 51 | Finish: 100 
Start: 11 | Finish: 50 
The sublist is: [53,59,61,67,71,73,79,83,89,97]
The sublist is: [11,13,17,19,23,29,31,37,41,43,47]
25    %no. of primes

但如果我调用 primes_parr(100,3),输出将变为无效。输出为:

List of primes(Lp): [3,5,7]
Start: 67 | Finish: 99 
Start: 34 | Finish: 66 
Start: 11 | Finish: 33 
The sublist is: [67,71,73,79,83,89,97]
The sublist is: [34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66]
The sublist is: [11,13,17,19,23,29,31]
35   %no. of primes

如果我将列表分成两个以上的部分,我想知道导致错误的原因。

【问题讨论】:

    标签: concurrency parallel-processing erlang sieve-of-eratosthenes sieve


    【解决方案1】:

    根据您的无效输出判断

    The sublist is: [67,71,73,79,83,89,97]
    The sublist is: [34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66] %% HERE
    The sublist is: [11,13,17,19,23,29,31]

    somewhere您的代码假定要筛选的范围的起始编号奇数

    确实,

    leaf(Pid_stem, Leaf_id, First, Last, Leaf_nums, []) -> 
        L = ordsets:subtract(lists:seq(First,Last,2),lists:usort(Leaf_nums)), 
        io:fwrite("The sublist is: ~w~n", [L]),
        Pid_stem ! {leaf_done, Leaf_id, length(L)};      %% reuse the L !!
    

    在计算lists:seq(<b>First</b>,Last,<b>2</b>) 时,假设First 是奇数。

    这应该很容易解决。只需将1 添加到First,如果它是偶数,则在您在leaf_spawn 中计算后立即。 (edit: 最好在此处输入 leaf,这样它的要求就可以清楚地看到并由它自己执行)。

    此外,有时Lp 中的最大素数也包含在最低块中的第一个素数中(例如,N=121N=545)。

    【讨论】:

      猜你喜欢
      • 2021-05-22
      • 2010-09-13
      • 1970-01-01
      • 2021-05-27
      • 1970-01-01
      • 2021-10-29
      • 2011-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多