【问题标题】:working in different directories (os.chdir) in the same time (parallel threading)同时在不同的目录(os.chdir)中工作(并行线程)
【发布时间】:2012-11-25 07:34:11
【问题描述】:

我想并行同步我所有的 vcs 目录。我将进入目录并运行特殊的命令行脚本来同步 git 或 mercurial 存储库。这是一个缓慢的过程,所以我想尝试使其并行。

但是我的并行线程争夺“当前目录”有问题,所以我需要一些技巧来同时在不同的目录中工作。

目前的解决方案:

def syncrepos(repos):
  for r in repos.split("\n"):
    if r:
      print("------ repository: ", r)
      thrd = ThreadingSync(r)
      thrd.setDaemon(True)
      thrd.start()

ThreadingSync 在哪里

class ThreadingSync(threading.Thread):
  def __init__(self, repo):
    threading.Thread.__init__(self)
    self.repo = repo
  def run(self):
    r = self.repo.split("-t")
    path = (r[0]).strip()
    if len(r) < 2:
      vcs = VCS.git
    else:
      vcs = {
    'git'       : VCS.git,
    'git git'   : VCS.git_git,
    'git hg'    : VCS.git_mercurial,
    'git svn'   : VCS.git_subversion,
    'git vv'    : VCS.git_veracity,
    'hg hg'     : VCS.hg_hg}[(r[1]).strip()]
    os.chdir(path)
    if vcs == VCS.git:
      checkGitModifications()
      gitSync()
    ... etc

gitSync

def gitSync(): 
  pretty(cmd("git pull origin master"))
  pretty(cmd("git fetch upstream master"))
  pretty(cmd("git pull --rebase upstream master"))
  pretty(cmd("git push -f origin master"))

当然,这并不完美,但它完成了我的工作,我想加快速度。

如何为每个存储库/目录生成一个子进程(os.chdir 的安全实现)?

【问题讨论】:

  • 有什么问题?您的代码相当不透明。到目前为止,我最好的建议是(a)考虑多处理模块而不是线程模块 - 它可能更容易开始,并且(b)为每个存储库/目录生成一个子进程,这样你就不必担心他们会互相绊倒。
  • @John Mee“为每个存储库/目录生成一个子进程” - 这就是我所需要的,这就是问题的全部内容。怎么办?
  • @John Mee os.chdir(path) 在我的 Threading 类中,但它仍在影响其他进程,以为 os.chrdir 会影响一些全局变量,但如何处理呢?
  • 你是说当你在子进程中改变目录时,当前目录在所有子进程中都会改变?有趣 :-) 那么完整的路径呢?
  • 完整路径将无法正常工作......我需要线程安全的 os.chdir 替代方案......我想。

标签: python multithreading parallel-processing directory multiprocessing


【解决方案1】:

创建一个工人池来运行您的子例程:

http://docs.python.org/2/library/multiprocessing.html#using-a-pool-of-workers

在你的情况下可能是这样的:

from multiprocessing import Pool
import os

def gitSync(repo):
    print "I am", repo, "and my cwd is:", os.getcwd()
    os.chdir(repo)
    print "I am", repo, "and my cwd is:", os.getcwd()

if __name__ == '__main__':
    dir = os.getcwd()
    repos = [item for item in os.listdir(dir) if os.path.isdir(os.path.join(dir, item))]
    print repos
    pool = Pool(maxtasksperchild=1)
    pool.map(gitSync, repos)
    pool.close()
    pool.join()

请注意,池可能会使调试变得有点困难,因为父级通常不会透露更多信息——我的一个孩子死了——所以先让它单线程工作。

编辑: 嗯,这很有趣 - 请注意 Pool maxtasksperchild=1 的新参数。该进程在调用之间不是rebooted,因此当您在一次调用中更改目录时,当进程被重用时,您仍在该目录中。在这里,我通过告诉池在每次调用后终止进程来解决它。

john:captcrunch john$ python foo.py 
['.git', '.idea', 'fixtures', 'lib', 'obj', 'raw', 'tests']
I am .git and my cwd is: /Users/john/code/linz/src/captcrunch
I am .git and my cwd is: /Users/john/code/linz/src/captcrunch/.git
I am .idea and my cwd is: /Users/john/code/linz/src/captcrunch
I am .idea and my cwd is: /Users/john/code/linz/src/captcrunch/.idea
I am fixtures and my cwd is: /Users/john/code/linz/src/captcrunch
I am fixtures and my cwd is: /Users/john/code/linz/src/captcrunch/fixtures
I am lib and my cwd is: /Users/john/code/linz/src/captcrunch
I am lib and my cwd is: /Users/john/code/linz/src/captcrunch/lib
I am obj and my cwd is: /Users/john/code/linz/src/captcrunch
I am obj and my cwd is: /Users/john/code/linz/src/captcrunch/obj
I am raw and my cwd is: /Users/john/code/linz/src/captcrunch
I am raw and my cwd is: /Users/john/code/linz/src/captcrunch/raw
I am tests and my cwd is: /Users/john/code/linz/src/captcrunch
I am tests and my cwd is: /Users/john/code/linz/src/captcrunch/tests

【讨论】:

  • 这将如何解决我的问题?例如:它会使 os.chdir 线程安全吗?
  • 抱歉,我们现在正在交叉发布 cmets;我的错...在问题下查看我的问题。
  • maxtasksperchild=1 真的是并行的吗?
  • 是的。每个核心将同时运行单独的进程,它只是指定您不介意在每次调用时创建一个新进程的开销。在合适大小的套装上试一试。你会看到所有的核心都被使用了。我还没有达到 I/O 饱和度(诚然 i7 带有 SSD)。
猜你喜欢
  • 2013-09-13
  • 1970-01-01
  • 1970-01-01
  • 2019-06-18
  • 2021-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多