bash - 令人尴尬的并行工作流创建了太多的输出文件

标签 bash file-io parallel-processing embarrassingly-parallel

在Linux群集上,我运行许多(N > 10^6)独立计算。每次计算仅需花费几分钟,并且输出只有几行。当N很小时,我可以将每个结果存储在一个单独的文件中,以便稍后解析。但是,使用大N时,我发现我在浪费存储空间(用于创建文件),并且由于bash的内部限制,像ls这样的简单命令需要格外小心。

每次计算都需要通过-bash: /bin/ls: Argument list too long调度算法来运行,因此我无法创建将输出数据简单地聚合到单个文件中的主程序。当两个程序同时完成并交织其输出时,追加到单个对象的简单解决方案将失败。我没有对该群集的管理员访问权限,因此无法选择安装系统范围的数据库。

如何在无法管理之前整理令人尴尬的并行计算的输出数据?

最佳答案

1)正如您所说,不是ls出现故障;它是启动ls之前进行glob扩展的外壳。您可以使用以下方法轻松解决此问题:

find . -type f -name 'GLOB' | xargs UTILITY


例如。:

find . -type f -name '*.dat' | xargs ls -l


您可能要对输出进行排序,因为find(出于效率考虑)不对文件名进行排序(通常)。 find(还有设置目录递归深度,以更复杂的方式进行过滤等)和xargs(每次调用的最大参数数目,并行执行等)还有许多其他选项。阅读man页面以获取详细信息。

2)我不知道您如何创建单个文件,因此提供特定的解决方案有点困难,但是这里有一些想法:


如果您可以自己创建文件,则可以将文件创建延迟到工作结束(例如,通过缓冲输出),并且文件存储在支持咨询锁定或其他锁定机制(例如原子链接)的文件系统中,那么您可以通过在输出输出之前将其锁定然后解锁来将各种作业多路复用到一个文件中。但这是很多要求。在群集中,您可能可以使用单个文件来完成在单个主机上运行的所有作业的操作,但是您可能又不能这样做。
同样,如果您自己创建文件,则可以自动将每一行写入共享文件。 (即使NFS支持原子写入,但也不支持原子附加,请参见下文。)您需要在每行前添加一个唯一的作业标识符,以便可以对其进行多路分解。但是,如果您使用某种自动机制,例如“我的工作写入stdout然后调度框架将其复制到文件中”,这将是不常见的,那么这将不起作用。 (实质上,此建议与MapReduce策略非常相似。也许您可以使用?)
如果没有其他一切,也许您只能使用子目录。数千个文件的数千个目录比一个拥有几百万个文件的目录更易于管理。


祝好运。

根据要求编辑,有关2.2的更多详细信息:

为此,您需要使用Posix I / O函数,因为afaik,C库不提供原子写入。在Posix中,只要打开文件时指定O_APPENDwrite函数总是自动进行写操作。 (实际上,无论如何它都会自动进行写操作,但是如果您未指定O_APPEND,则每个进程都将其自身位置保留在文件中,因此它们最终将相互覆盖。)

因此,您需要做的是:


在程序的开头,open一个带有选项O_WRONLY|O_CREATE|O_APPEND的文件。 (与我之前所说的相反,这不能保证可以在NFS上使用,因为NFS可能无法正确处理O_APPEND。较新版本的NFS在理论上可以处理仅附加文件,但它们可能无法处理。过一会儿。)您可能不希望总是使用相同的文件,因此请在其名称中的某个位置放置一个随机数,以便您的各种作业有多种选择。 O_CREAT始终是原子的,即使使用糟糕的NFS实现也是如此。
对于每个输出行,sprintf将该行连接到内部缓冲区,并在开始处放置一个唯一的ID。 (您的工作必须具有某种唯一的ID;请使用该ID。)[如果您偏执,请以某种记录分隔符作为开始行,然后在其余行中增加字节数-您必须在格式化后放入此值-因此该行的外观类似于^0274:xx3A7B29992A04:<274 bytes>\n,其中^是十六进制的01或类似的字符。
write文件的整行。检查返回码和写入的字节数。如果写入失败,请重试。如果写的很短,希望您按照上面的“如果您很偏执”的说明进行操作,也可以再试一次。


确实,您不应写短篇小说,但您永远不会知道。编写长度非常简单;解复用有点复杂,但是当您需要:)时,您可以越过那座桥

使用NFS的问题有点烦人。与2.1一样,最简单的解决方案是尝试在本地写入文件,或使用一些正确支持append的群集文件系统。 (NFSv4允许您仅请求“追加”许可权,而不是“写入”许可权,如果其他某个进程已经设法写入要使用的偏移量,则这将导致服务器拒绝写入。在这种情况下,您需要需要寻找到文件的末尾并再次尝试写入,直到最终成功为止。但是,我给人的印象是该功能并未真正实现。我可能是错的。)

如果文件系统不支持追加,则还有另一种选择:确定行长,并始终写入该字节数。 (显然,如果选定的固定行长度比最长的行长,会更容易,但是只要有序列号,就可以写入多条固定长度的行。)您需要保证每个作业的写入位置均为您可以通过将作业的作业编号划分为文件编号和交错编号,然后将特定作业的所有行以交错编号为模数的方式写到文件中来进行不同的偏移,该文件的名称包括文件编号。 (如果按顺序编号作业,这是最简单的方法。)可以在文件末尾进行写入,因为Unix文件系统将-或至少应该-插入NUL或创建不连续的文件(这样会浪费更少的空间,但是取决于文件的块大小)。

处理不支持附加但确实支持咨询性字节范围锁定(NFSv4支持此功能)的文件系统的另一种方法是使用固定行长方法,如上所述,但在之前要写入的范围上获得锁定写。使用非阻塞锁,如果无法获得该锁,请在下一个行偏移倍数处重试。如果可以获得锁,请在该偏移量处读取文件,以在写入之前验证它是否没有数据;然后释放锁。

希望能有所帮助。

关于bash - 令人尴尬的并行工作流创建了太多的输出文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13608816/

相关文章:

c - 如何读取文件的第一个数字?

python - aiohttp 优于 pycurl multi,因为 python 有 gil,切换到 aiohttp 可以获得什么好处?

Java MPI 广播

bash - 将传感器输出提取到排序数组中

regex - Sed 替换 URL 中的域

bash - os.exec.Command 和 pbcopy

java - java中如何替换文件内容?

file - 使用 GWT 列出目录中的文件

Python 与 selenium 并行执行

从 R 脚本运行 bash 脚本