You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Erlang并发蒙特卡洛Pi值估算(多Actor与迭代数)实现问题咨询

Alright, let's figure out how to build that concurrent Monte Carlo Pi estimator in Erlang. You already have the non-concurrent version down, so we just need to split the work across X actors, collect their results, and crunch the final number. Here's a step-by-step solution with code and explanations:

Step 1: Core Idea

Instead of handling all N points in one process, we split the workload into X chunks. Each actor handles a subset of the points, counts how many fall inside the unit circle, and sends that count back to the main process. The main process sums all the counts and calculates Pi using the same formula as your non-concurrent version: 4 * (total_count / N).

Step 2: Full Concurrent Implementation

Here's a complete module that includes both your original non-concurrent function and the new concurrent one:

-module(pi_montecarlo).
-export([montecarlo/1, montecarlo/2]).

% Non-concurrent version (your original logic)
montecarlo(N) ->
    montecarlo(N, 1).

% Concurrent version: N total points, X actors
montecarlo(N, X) when X > 0, N > 0 ->
    PerActor = N div X,
    Remainder = N rem X,
    % Spawn first X-1 workers with equal point counts
    Pids = spawn_workers(X-1, PerActor, self()),
    % Spawn last worker to handle any remaining points
    LastPid = spawn_worker(PerActor + Remainder, self()),
    AllPids = [LastPid | Pids],
    % Gather results from all workers
    TotalCount = collect_results(AllPids, 0),
    % Calculate final Pi estimate
    4 * (TotalCount / N).

spawn_workers(0, _, _) -> [];
spawn_workers(Num, Points, Parent) ->
    Pid = spawn_worker(Points, Parent),
    [Pid | spawn_workers(Num-1, Points, Parent)].

spawn_worker(Points, Parent) ->
    spawn(fun() -> worker(Points, Parent) end).

worker(Points, Parent) ->
    % Initialize unique random seed for each worker
    <<A:32, B:32, C:32>> = crypto:strong_rand_bytes(12),
    rand:seed(exsplus, {A,B,C}),
    Count = count_in_circle(Points, 0),
    Parent ! {self(), Count}.

count_in_circle(0, Count) -> Count;
count_in_circle(PointsLeft, Count) ->
    X = rand:uniform(),
    Y = rand:uniform(),
    case X*X + Y*Y =< 1.0 of
        true -> count_in_circle(PointsLeft-1, Count+1);
        false -> count_in_circle(PointsLeft-1, Count)
    end.

collect_results([], Total) -> Total;
collect_results([Pid | Rest], Total) ->
    receive
        {Pid, Count} -> collect_results(Rest, Total + Count)
    end.

Step 3: Breakdown of Key Parts

  • montecarlo/2 (Main Function):

    • Splits the total points N into equal chunks, and handles any remainder by assigning extra points to the last worker. This ensures we process all N points without missing any.
    • Spawns all worker processes and waits to collect their results.
  • Worker Processes:

    • Each worker initializes its own random seed using crypto:strong_rand_bytes—this avoids duplicate random sequences across processes, which is critical for getting accurate Pi estimates.
    • Runs the same point-counting logic as your non-concurrent code, but only for its assigned subset of points.
    • Sends its final count back to the main process as a message tagged with its PID.
  • Result Collection:

    • The main process waits to receive a message from each specific worker PID, sums up all the counts, and computes the final Pi value using the standard Monte Carlo formula.

Step 4: Testing It Out

Try running these commands in the Erlang shell to see it in action:

% Non-concurrent (original behavior)
pi_montecarlo:montecarlo(1000000).

% Concurrent with 4 actors
pi_montecarlo:montecarlo(1000000, 4).

You should notice the concurrent version runs faster (especially with larger N) since the work is spread across multiple processes.

Notes to Keep in Mind

  • The guard clause when X > 0, N > 0 ensures we only accept valid positive integers for both parameters.
  • Using crypto:strong_rand_bytes for seed initialization is more reliable than timestamps, as it guarantees unique seeds for every worker.
  • The result collection logic is tied to specific worker PIDs, so you don't have to worry about missing or misordering results.

内容的提问来源于stack exchange,提问作者Anthony Nicastro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:13:43