Python(或者通常是linux)文件操作流控制或文件锁定

时间:2012-01-22 04:24:28

标签: 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]

对于一些额外的控制,ruby代码在将bash脚本写入q目录后会在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,这是它的挂载信息 :/ home / 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

2 个答案:

答案 0 :(得分:1)

  

我知道这不是协调计算的优雅方式,但我   还没有找到更好的沟通方式   机等。

虽然这不是您所问的直接问题,但您应该真的考虑在此级别修复您的问题,使用某种共享消息队列可能是批次< / em>比依赖特定网络文件系统的锁定语义更易于管理和调试。

根据我的经验设置和运行的最简单的解决方案是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

有关计算需求和运行环境的更多细节,可以推荐更简单的方法来管理它。

答案 1 :(得分:0)

尝试一下while循环?如果这不起作用,在python端尝试使用如下的TRY语句:

Try:
     with open("myfile.whatever", "r") as f:
          f.read()
except:
     (do something if it doesnt work, perhaps a PASS? (must be in a loop to constantly     check this)

else:
    execute your code if successful