Parallel processing 如何使用Erlang以分布式方式读取二进制文件?

Parallel processing 如何使用Erlang以分布式方式读取二进制文件?,parallel-processing,erlang,binary-data,Parallel Processing,Erlang,Binary Data,我有几个中等大小(1到5GB)的二进制文件,我想使用Erlang读取和处理这些文件 每个文件都有不同大小的记录,即一条记录的大小为200 kb,而另一条记录的大小可能为800 kb。记录大小可以通过读取记录的前几个字节来获得。由于它是一个二进制文件,所以两个记录之间没有分隔符 为了处理这些文件,我们可以编写多线程程序,但为了好玩,我想到了使用Erlang并行处理文件 我是Erlang的新手,所以我不知道如何将文件分割成块并将这些块传递给Erlang进程 任何人都可以提供一些想法吗?为什么不为每个

我有几个中等大小(1到5GB)的二进制文件,我想使用Erlang读取和处理这些文件

每个文件都有不同大小的记录,即一条记录的大小为200 kb,而另一条记录的大小可能为800 kb。记录大小可以通过读取记录的前几个字节来获得。由于它是一个二进制文件,所以两个记录之间没有分隔符

为了处理这些文件,我们可以编写多线程程序,但为了好玩,我想到了使用Erlang并行处理文件

我是Erlang的新手,所以我不知道如何将文件分割成块并将这些块传递给Erlang进程


任何人都可以提供一些想法吗?

为什么不为每个文件启动一个流程?我看不出将小文件分割成块的价值。你的文件已经很小了。这也可以在许多机器上并行化。

我在其他编程语言中也做过很多次,在Erlang中这是一个有趣的学习练习

基本策略是告诉每个进程它的起始字节偏移量、记录大小和要读取的记录数。(如果一个文件中有不同大小的记录,则可能会传递一个记录大小列表,如
[200800800800800800800200100]
)。工人独立处理他们的区块,并将结果返回给父级

我认为这很容易,你可以自己解决。您需要将
erlang:spawn
文件:open
文件:read
文件:position
作为主要部分。但是如果你想要破坏者,这里是我的一个模块的实现,它从一个二进制文件中读取数字,并使用多个进程找到平均值。(我不是Erlang专家,所以可能有更好的方法。)


一般来说,我会让一个“阅读器”进程读取记录,然后将它们发送给一个或多个工作进程。通过将繁重的工作(读后处理)转移到不同的进程/核心,这限制了阅读过程必须做的额外工作量(从而确保它的阅读速度尽可能快)。很抱歉,回复太晚了。我在过圣诞节。非常感谢分享您的知识。我正在我的机器上尝试你的程序,很快会让你知道我的结果。
-module(average).

-export([write_file/3, read_file/4]).
-export([read_file_worker/5]).

write_file(Filename, BlockSize, ListOfNumbers) ->
    BS = BlockSize*8,
    BinData = [<<X:BS>> || X <- ListOfNumbers],
    {ok, IoDevice} = file:open(Filename, [write, raw, binary]),
    file:write(IoDevice, BinData),
    file:close(IoDevice).

read_file(Filename, BlocksPerProcess, BlockSize, TotalBlockCount) ->
    {ok, SpawnCount} = read_file_spawner(Filename, BlocksPerProcess, BlockSize, TotalBlockCount, 0, 0),
    {ok, Sum} = read_file_listener(SpawnCount, 0),
    io:format("Total sum: ~p~nNumbers seen: ~p~nAverage: ~p~n", [Sum, TotalBlockCount, Sum/TotalBlockCount]).

read_file_spawner(Filename, BlocksPerProcess, BlockSize, TotalBlockCount, BlockOffset, SpawnCount) when BlockOffset < TotalBlockCount ->
    Offset = BlockOffset * BlockSize,
    MaxBlocks = min(BlocksPerProcess, TotalBlockCount - BlockOffset),
    spawn(?MODULE, read_file_worker, [self(), Filename, Offset, BlockSize, MaxBlocks]),
    read_file_spawner(Filename, BlocksPerProcess, BlockSize, TotalBlockCount, BlockOffset + BlocksPerProcess, SpawnCount + 1);
read_file_spawner(_Filename, _BlocksPerProcess, _BlockSize, _TotalBlockCount, _BlockOffset, SpawnCount) ->
    {ok, SpawnCount}.

read_file_listener(0, Accum) ->
    {ok, Accum};
read_file_listener(SpawnCount, Accum) ->
    receive
    {ok, Number} ->
        io:format("Got ~p~n", [Number]),
        read_file_listener(SpawnCount - 1, Accum + Number)
    end.

read_file_worker(MasterPid, Filename, Offset, BlockSize, MaxBlocks) ->
    {ok, IoDevice} = file:open(Filename, [read, raw, binary]),
    {ok, Offset} = file:position(IoDevice, {bof, Offset}),
    {ok, Sum} = read_file_worker_loop(IoDevice, BlockSize, 0, MaxBlocks, 0),
    MasterPid ! {ok, Sum}.

read_file_worker_loop(IoDevice, BlockSize, BlocksRead, MaxBlocks, Accum) when BlocksRead < MaxBlocks ->
    {ok, BinData} = file:read(IoDevice, BlockSize),
    Number = binary:decode_unsigned(BinData),
    read_file_worker_loop(IoDevice, BlockSize, BlocksRead + 1, MaxBlocks, Accum + Number);
read_file_worker_loop(_IoDevice, _BlockSize, _BlocksRead, _MaxBlocks, Accum)  ->
    {ok, Accum}.
12> Numbers = [1,1,2,4,6,10,10,1,0,500].                                  
[1,1,2,4,6,10,10,1,0,500]
13> average:write_file("/tmp/test.binary", 32, Numbers).                  
ok
14> average:read_file("/tmp/file.binary", 2, 32, length(Numbers)).        
Got 500
Got 11
Got 6
Got 16
Got 2
Total sum: 535
Numbers seen: 10
Average: 53.5
ok