在进程之间传递资源锁的最佳方式
Best way to communicate resource lock between processes
我有两个 python 程序应该并行 运行 并做同样的事情:
- 从磁盘读取和解压缩数据(大约需要 1 分钟)
- 处理数据(大约需要 2-3 分钟)
- 将数据发送到数据库(大约需要 3-5 分钟)
如您所见,如果两个实例的执行以一种执行处理器繁重的步骤 1 和 2 的方式同步(实现是多线程的,因此 CPU 可以实际上是最大化),而另一个执行 I/O-heavy 第 3 步,反之亦然。
我的第一个想法是使用锁文件,每个进程在进入阶段3时获取并在完成后释放。所以其他进程会一直等到锁被释放,然后在进入阶段3的时候再设置。不过,这似乎是一种非常繁琐的做法。此外,系统应该 运行 数天和数周不受监督,能够从错误、计划的重启或电源故障中恢复。特别是在最后一种情况下,锁文件可以简单地锁定所有内容。
是否有更优雅的方式来传达两个进程之间的锁定?或者我应该使用锁文件并尝试实现一些智能清理功能来防止死锁发生?
如果你是运行一些同步问题,在我看来没有比使用信号量更好的方法了。您处理清理和锁定部件的方式在很大程度上取决于您的问题。这类问题有很多资源。 Python 已经实施了一些 primitives
您可以查看此 post 作为示例。
另请检查 Zookeeper,我从未在 python 上使用它,但它在其他语言中广泛使用。
似乎每个解决方案都有一些缺点 - 某些机制或模块并非在所有平台上都可用(即仅 Linux 或仅 Windows),或者您可能 运行使用基于文件系统的方法解决错误恢复问题(正如您已经在问题中指出的那样)。
这里列出了一些可能的选项:
使用Python的multiprocessing
模块
这允许您像这样创建一个锁:
lock = multiprocessing.Lock()
并像这样获取和释放它:
lock.acquire()
# do something
lock.release()
Here is一个完整的例子。
Pro: 使用简单;跨平台;错误恢复没有问题。
缺点: 由于您目前有两个独立的程序,您将不得不重新安排代码以从同一个 python 模块启动两个进程。
使用fnctl
(Linux)
对于 Linux/Unix 系统,有 fcntl(fcntl.flock()
)作为 python 模块可用。这是基于锁文件。
另请参阅 this discussion 以及我在此重复的一些建议:
- 将锁定进程的进程 ID 写入文件,以便能够识别和修复可能的死锁。
- 将您的锁定文件放在临时位置或 RAM 文件系统中。
缺点: 不能跨平台,仅在 Linux/Unix 系统上可用。
使用posix_ipc
(Linux)
对于 Linux/Unix 系统,python_ipc(具有 Semaphore
class)可作为 python 模块使用。
专业版:不是基于文件系统的,错误恢复没有问题。
缺点: 不能跨平台,仅在 Linux/Unix 系统上可用。
使用msvcrt
(Windows)
对于 Windows 系统,msvcrt(带有 msvcrt.locking()
)可作为 python 模块使用。
另见 。
缺点: 不能跨平台,仅在 Windows 系统上可用。
使用第三方库
您可能需要检查以下 python 个库:
我有两个 python 程序应该并行 运行 并做同样的事情:
- 从磁盘读取和解压缩数据(大约需要 1 分钟)
- 处理数据(大约需要 2-3 分钟)
- 将数据发送到数据库(大约需要 3-5 分钟)
如您所见,如果两个实例的执行以一种执行处理器繁重的步骤 1 和 2 的方式同步(实现是多线程的,因此 CPU 可以实际上是最大化),而另一个执行 I/O-heavy 第 3 步,反之亦然。
我的第一个想法是使用锁文件,每个进程在进入阶段3时获取并在完成后释放。所以其他进程会一直等到锁被释放,然后在进入阶段3的时候再设置。不过,这似乎是一种非常繁琐的做法。此外,系统应该 运行 数天和数周不受监督,能够从错误、计划的重启或电源故障中恢复。特别是在最后一种情况下,锁文件可以简单地锁定所有内容。
是否有更优雅的方式来传达两个进程之间的锁定?或者我应该使用锁文件并尝试实现一些智能清理功能来防止死锁发生?
如果你是运行一些同步问题,在我看来没有比使用信号量更好的方法了。您处理清理和锁定部件的方式在很大程度上取决于您的问题。这类问题有很多资源。 Python 已经实施了一些 primitives
您可以查看此 post 作为示例。
另请检查 Zookeeper,我从未在 python 上使用它,但它在其他语言中广泛使用。
似乎每个解决方案都有一些缺点 - 某些机制或模块并非在所有平台上都可用(即仅 Linux 或仅 Windows),或者您可能 运行使用基于文件系统的方法解决错误恢复问题(正如您已经在问题中指出的那样)。
这里列出了一些可能的选项:
使用Python的multiprocessing
模块
这允许您像这样创建一个锁:
lock = multiprocessing.Lock()
并像这样获取和释放它:
lock.acquire()
# do something
lock.release()
Here is一个完整的例子。
Pro: 使用简单;跨平台;错误恢复没有问题。
缺点: 由于您目前有两个独立的程序,您将不得不重新安排代码以从同一个 python 模块启动两个进程。
使用fnctl
(Linux)
对于 Linux/Unix 系统,有 fcntl(fcntl.flock()
)作为 python 模块可用。这是基于锁文件。
另请参阅 this discussion 以及我在此重复的一些建议:
- 将锁定进程的进程 ID 写入文件,以便能够识别和修复可能的死锁。
- 将您的锁定文件放在临时位置或 RAM 文件系统中。
缺点: 不能跨平台,仅在 Linux/Unix 系统上可用。
使用posix_ipc
(Linux)
对于 Linux/Unix 系统,python_ipc(具有 Semaphore
class)可作为 python 模块使用。
专业版:不是基于文件系统的,错误恢复没有问题。
缺点: 不能跨平台,仅在 Linux/Unix 系统上可用。
使用msvcrt
(Windows)
对于 Windows 系统,msvcrt(带有 msvcrt.locking()
)可作为 python 模块使用。
另见
缺点: 不能跨平台,仅在 Windows 系统上可用。
使用第三方库
您可能需要检查以下 python 个库: