Python(或一般的 linux)文件操作流控制或文件锁定

标签 python filesystems parallel-processing

我正在使用一组计算机进行一些并行计算。我的主目录在整个集群中共享。在一台机器上,我有一个 ruby​​ 代码,它创建包含计算命令的 bash 脚本,并将脚本写入 ~/q/目录。这些脚本被命名为 *.worker1.sh、*.worker2.sh 等。

在其他 20 台机器上,我运行了 20 个 python 代码(每台机器一个),它们(不断地)检查 ~/q/目录并查找属于该机器的作业,使用如下 python 代码:

jobs = glob.glob('q/*.worker1.sh')
[os.system('sh ' + job + ' &') for job in jobs]

对于一些额外的控制,在将 bash 脚本写入 q 目录后,ruby 代码将在 q 目录创建一个空文件,如 workeri.start (i = 1..20),python 代码将检查'start ' 文件在运行上面的代码之前。在 bash 脚本中,如果命令成功完成,bash 脚本将创建一个空文件,如“workeri.sccuess”,python 代码在运行上述代码后检查此文件以确保计算成功完成。如果 python 发现计算成功完成,它将删除 q 目录中的 'start' 文件,因此 ruby​​ 代码知道作业成功完成。 20个bash脚本全部完成后,ruby代码会创建新的bash脚本,python会读取并执行新的脚本等等。

我知道这不是协调计算的优雅方式,但我还没有想出更好的方式来在不同机器之间进行通信。

现在的问题是:我预计这 20 个作业将在一定程度上并行运行。完成 20 项工作的总时间不会比完成一项工作的时间长很多。然而,这些作业似乎是顺序运行的,时间比我预期的要长得多。

我怀疑部分原因是多个代码同时读写同一个目录,但linux系统或python锁定了该目录,只允许一个进程操作该目录。这使得代码一次执行一个。

我不确定是不是这样。如果我将bash脚本拆分到不同的目录,让不同机器上的python代码读写不同的目录,是不是就可以解决问题了?还是有其他原因导致的问题?

非常感谢您的任何建议!如果我没有解释清楚,请告诉我。

一些附加信息: 我的主目录在/home/my_group/my_home,这是它的挂载信息 :/vol/my_group on/home/my_group type nfs (rw,nosuid,nodev,noatime,tcp,timeo=600,retrans=2,rsize=65536,wsize=65536,addr=...)

我说不断检查 q 目录,意思是像这样的 python 循环:

While True:
    if 'start' file exists:
        find the scripts and execute them as I mentioned above

最佳答案

I know this is not a elegant way to coordinate the computation, but I haven't figured out a better to communicate between different machines.

虽然这不是您直接提出的问题,但您真的应该真的考虑在这个级别上解决您的问题,使用某种共享消息队列可能很多 比依赖特定网络文件系统的锁定语义更易于管理和调试。

根据我的经验,最简单的设置和运行解决方案是 redis在当前运行创建作业的 Ruby 脚本的机器上。从字面上看,它应该像下载源代码一样简单,编译它并启动它。一旦 redis 服务器启动并运行,您就可以更改代码以将计算命令附加到一个或多个 Redis 列表。在 ruby 中你会使用 redis-rb像这样的库:

require "redis"

redis = Redis.new
# Your other code to build up command lists...
redis.lpush 'commands', command1, command2...

如果计算需要由某些机器处理,请使用像这样的每台机器列表:

redis.lpush 'jobs:machine1', command1
# etc.

然后在您的 Python 代码中,您可以使用 redis-py连接到 Redis 服务器并将作业从列表中拉出,如下所示:

from redis import Redis
r = Redis(host="hostname-of-machine-running-redis")
while r.llen('jobs:machine1'):
    job = r.lpop('commands:machine1')
    os.system('sh ' + job + ' &')

当然,您可以轻松地从队列中取出作业并在 Ruby 中执行它们:

require 'redis'
redis = Redis.new(:host => 'hostname-of-machine-running-redis')
while redis.llen('jobs:machine1')
    job = redis.lpop('commands:machine1')
    `sh #{job} &`
end

有了关于计算需求及其运行环境的更多详细信息,就可以推荐更简单的方法来管理它。

关于Python(或一般的 linux)文件操作流控制或文件锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8958939/

相关文章:

python - 有 Python 缓存库吗?

python - 如何使用正则表达式搜索和删除字符串?

c++ - C++17 在并行性方面到底做了什么改变? (权威文件在哪里?)

python - numpy.argmax 比 MATLAB [~,idx] = max() 慢吗?

java - 如何确定文件将被逻辑移动还是物理移动

python - 扩展在文件系统中存储文件的应用程序时需要考虑什么?

c++ - 如何判断文件刷新在关闭文件之前确实有效?

python - 使用并行运行 html2text

具有大共享数据的 Python 多处理

Python上下文管理的成员变量?