【问题标题】:paralellizing svn up causing client freeze并行 svn up 导致客户端冻结
【发布时间】:2014-12-29 10:54:36
【问题描述】:

我正在编写一个程序来并行运行svn up,它导致机器死机。发生这种情况时,服务器没有遇到任何负载问题。

这些命令使用ThreadPool.map() 运行到subprocess.Popen():

def cmd2args(cmd):
    if isinstance(cmd, basestring):
        return cmd if sys.platform == 'win32' else shlex.split(cmd)
    return cmd

def logrun(cmd):
    popen = subprocess.Popen(cmd2args(cmd),
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT,
                             cwd=curdir,
                             shell=sys.platform == 'win32')
    for line in iter(popen.stdout.readline, ""):
        sys.stdout.write(line)
        sys.stdout.flush()

...
pool = multiprocessing.pool.ThreadPool(argv.jobcount)
pool.map(logrun, _commands)

argv.jobcount 是multiprocessing.cpu_count() 和要运行的作业数(在本例中为 4)中的较小值。 _commands 是包含下面列出的命令的字符串列表。 shell 在 Windows 上设置为 True,因此 shell 可以找到可执行文件,因为 Windows 没有 which 命令,并且在 Windows 上查找可执行文件有点复杂(命令过去的形式为 @ 987654335@ 也需要 shell=True 但现在使用 cwd 参数代替)。

正在运行的命令是

  svn up w:/srv/lib/dktabular
  svn up w:/srv/lib/dkmath
  svn up w:/srv/lib/dkforms
  svn up w:/srv/lib/dkorm

每个文件夹是一个单独的项目/存储库,但存在于同一个 Subversion 服务器上。 svn 可执行文件是使用 TortoiseSVN 1.8.8(构建 25755 - 64 位)打包的。代码是最新的(即svn up 是无操作的)。

当客户端死机时,任务管理器中的内存条首先变为空白:

有时一切都会变暗

如果我等待一段时间(几分钟),机器最终会恢复正常。

Q1:并行调用svn 会不会很尴尬?

Q2:我使用ThreadPool.map() 和subprocess.Popen() 的方式有什么问题吗?

Q3:是否有任何工具/策略可以调试此类问题?

【问题讨论】:

  • 我建议不要将多个问题打包成一个问题(或者这样做不太明显),您只会从知道所有问题答案的人那里得到答案。
  • 感谢您的反馈。我的 Qn 列表是同一个问题的所有方面(即,如果您不能并行调用 svn,那么我如何称呼 TP.map() 并不重要),但当然,如果有人只知道部分答案那么请回答(我给所有有用的答案加分)。
  • 使用logging,查看脚本中发生了什么。在 Windows 上使用 iotop 的模拟来查看您的磁盘发生了什么。您可以安装类似glances 和/或Sysinternals tools 的东西。然后使用标准调试技术:阅读代码 测试你的理解程度 缩小问题范围。为什么使用shell=True 运行svn? (subprocess 可以找到svn 没有shell=True 的可执行文件吗?)
  • _commands' 是什么类型?你的 Python 版本是什么? argv.jobcount 有多大?捕获异常并记录它们。
  • @J.F.Sebastian 我已经用Popen 参数的信息更新了这个问题。我现在正在研究您的工具建议。 (谢谢)

标签: python windows svn


【解决方案1】:

我将尽我所能彻底回答所有三个问题,我欢迎更正我的陈述。

Q1:并行调用svn是不是很讨厌?

Copacci,这有待确定,但我想说,既不推荐也不推荐。根据该声明,源代码控制工具具有需要进程和块级(最佳猜测)锁定的特定功能。校验和、文件传输和文件读取/写入需要锁定才能正确处理,否则您将面临重复工作和文件争用的风险,这将导致进程失败。

Q2:我使用ThreadPool.map() 和subprocess.Popen() 的方式有什么问题吗?

虽然我不知道 subprocess.Popen() 的绝对细节,因为我上次在 2.6 中使用它,但我可以谈谈可编程性。您在创建的代码中所做的是创建一个包含一个特定子进程的池,而不是直接调用这些进程。现在我不禁想到,根据我对ThreadPool() 的理解,它默认不执行锁定。这可能会导致subprocess.Popen() 出现问题,我不确定。关于我上面的回答,锁定是需要实现的。我建议查看https://stackoverflow.com/a/3044626/2666240,以便更好地了解线程和池之间的差异,因为我建议使用线程而不是多处理。由于需要锁定的源代码控制应用程序的性质,如果您要在处理锁定的同时并行化操作,您还需要能够同步线程以便不重复工作。几个月前,我在 Linux 上进行了多处理测试,我注意到 grep 正在重复全局搜索。我会看看我是否能找到我写的代码并粘贴它。通过线程同步,我希望 Python 能够以 svn 能够理解的方式在线程之间传递 svn 线程状态,这样就不会发生进程重复。话虽这么说,我不知道 svn 在这方面是如何工作的,所以我只是在推测/做出最好的猜测。由于 svn 可能使用了一种相当复杂的锁定方法(我会断言块级锁定而不是 inode 锁定,但最好还是再次猜测一下),实现信号量锁定而不是 lock() 或 Rlock() 可能是有意义的。也就是说,您将不得不通过并测试各种锁定和同步方法来找出最适合 svn 的方法。在线程同步方面,这是一个很好的资源:@​​987654322@

Q3:是否有任何工具/策略可以调试此类问题?

当然,线程和多处理都应该具有可以与日志记录结合使用的日志记录功能。我只是登录到一个文件,这样你就可以有一些东西可以参考,而不仅仅是控制台输出。从理论上讲,您应该能够只使用logging.debug(pool.map(logrun, _commands)),这将记录所采取的进程。话虽如此,我不是线程或多处理方面的日志专家,所以其他人可能会比我更好地回答这个问题。

您使用的是 Python 2.x 还是 3.x?

【讨论】:

  • 我使用的是 Python 2.7.3。每次subprocess.Popen 调用,ThreadPool 都会启动约 1 个线程。我使用 ThreadPool 是因为它与进程版本相比是轻量级的,而且由于它所做的只是启动进程,因此 GIL 没有任何问题。每个 Popen 在可用的 cpu 内核上创建一个新的 svn 进程(释放 GIL 以便 ThreadPool 可以继续)。注意:svn 调用在不相交的存储库上运行,因此没有任何公共源文件的争用。
  • 我的两个假设是(i)svn 在某处有一些全局状态被破坏或(ii)我不断地吹走磁盘缓存..?
  • 我会断言全局状态是什么被覆盖/中断等。这是我目前最好的猜测。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多