我手头的任务是读取大文件的行,处理它们,并返回有序结果。
我的算法是:
- 从评估工作负载的主进程开始(写在文件的第一行)
- 生成工作进程:每个工作进程将使用 pread/3 读取文件的一部分,处理这部分,并将结果发送给 master
- master接收所有子结果,排序,返回
所以工人之间基本上不需要沟通。
我的问题:
- 如何找到erlang进程数和核心数之间的最佳平衡点?因此,如果我为每个处理器核心生成一个进程,我的 cpu 是否会被充分利用?
- pread/3如何到达指定行;它会迭代文件中的所有行吗? pread/3 是并行文件读取的好计划吗?
- 从进程A向B发送一条大消息好还是发送N条小消息好?我在下面的链接中找到了部分答案,但我希望进一步详细说明
Erlang消息传递架构 https://stackoverflow.com/questions/30710923/erlang-message-passing-architecture
-
Erlang 进程很便宜。您可以自由(并鼓励)使用超出您拥有的核心数量的核心。对于您的问题来说,实际情况可能存在上限(在每行一个进程中加载 1TB 的数据要求有点高,具体取决于行大小)。
当您不知道时,最简单的方法就是让用户决定。这意味着你可以决定生成N
工人,并在他们之间分配工作,等待回复。更改时重新运行程序N
如果你不喜欢它的运行方式。
更棘手的方法是对大量时间进行基准测试,选择您认为有意义的最大值,将其放入池库中(如果您愿意的话;有些池用于预分配资源,有些池用于可调整大小的资源),并选择一种一刀切的解决方案。
但实际上,不存在简单的“最佳核心数量”。您可以在 50 个进程上运行它,如果需要,也可以在其中 65,000 个进程上运行;如果任务是极其并行的,那么虚拟机应该能够利用其中的大部分任务并使核心饱和。
-
-
并行文件读取是一个有趣的问题。它可能会更快,也可能不会更快(正如直接评论所提到的),并且如果每行上的工作足够小以至于读取文件的成本最大,那么它可能只代表加速。
棘手的一点确实是这样的功能pread/2-3
需要一个字节偏移量。你的问题的措辞让你担心lines文件的。因此,您传递给工作人员的字节偏移量最终可能会跨越一条线。如果你的区块最终出现在这个词上my
in this is my line\nhere it goes\n
,一个工人会看到自己有一条不完整的线,而另一个工人只会报告my line\n
,缺少之前的this is
.
一般来说,这种烦人的事情会导致你让第一个进程拥有该文件并对其进行筛选,只是将要处理的文本片段交给工作人员;该流程将充当某种协调员。
该策略的好处在于,如果主进程知道作为消息发送的所有内容,那么它也知道何时收到所有响应,从而可以轻松知道何时返回结果。如果一切都是脱节的,那么你必须相信首发者和工人都会告诉你“我们都失业了”作为一组不同的独立消息来了解。
在实践中,您可能会发现最有帮助的是了解有关文件操作的有助于硬件寿命的操作,而不仅仅是“有多少人可以同时读取该文件”。只有一个硬盘(或SSD),所有数据无论如何都要经过它;最终访问的并行性可能会受到限制。
-
-
使用对您的程序有意义的消息。性能最佳的程序将拥有许多能够完成工作的进程,而无需传递消息、通信或获取锁。
一个更现实的高性能程序将使用非常少的非常小的消息。
这里有趣的是,你的问题本质上是基于数据的。所以你可以做一些事情:
- 确保您以二进制格式读取文本;大型二进制文件(> 64b)在全局二进制堆上分配,通过引用计数进行共享和 GC
- 提交有关需要做什么的信息,而不是执行该操作的数据;这个需要测量,但是主导进程可以检查文件,记下行结束的位置,然后将字节偏移量交给工作人员,以便他们可以自己读取文件;请注意,您最终将读取文件两次,因此如果内存分配不是您的主要开销,这可能会更慢
- 确保文件已读入
raw
or ram
模式;其他模式使用中间人进程来读取和转发数据(如果您通过集群 Erlang 节点中的网络读取文件,这非常有用);raw
and ram
模式将文件描述符直接提供给调用进程,并且速度要快得多。
- 首先要担心编写一个清晰、可读且正确的程序。只有当它太慢时才应该尝试重构和优化它;第一次尝试时您很可能会发现它足够好。
我希望这有帮助。
附:您可以首先尝试非常简单的方法:
-
either:
- 立即读取整个文件
{ok, Bin} = file:read_file(Path)
和分割线(与binary:split(Bin, <<"\n">>, [global])
),
- use
{ok, Io} = file:open(File, [read,ram])
然后使用file:read_line(Io)
重复地在文件描述符上
- use
{ok, Io} = file:open(File, [read,raw,{read_ahead,BlockSize}])
然后使用file:read_line(Io)
重复地在文件描述符上
call rpc:pmap({?MODULE, Function}, ExtraArgs, Lines)
自动并行运行所有内容(它将每行生成一个进程)
call lists:sort/1
关于结果。
然后,如果您发现每个步骤有问题,您可以从那里完善它们。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)