4

我目前有一个 global Lock = threading.Lock(),并拨打以下电话:

Parallel(n_jobs=2)(delayed(serialRemove)(dir,c,b,l,f) for f in os.listdir(dir))

使用工作库。中serialRemove,我有

Lock.acquire()
print(f+' begin')
if h in hashes:
    try:
        os.remove(path)
        if l: print('Removing ' + path)
        removed += 1
    except os.error:
        print('Encountered error removing file') 
else:
    hashes.add(h)
print(f+' end')
Lock.release()

部分调用导致:
10.txt begin
11.txt begin
20.txt begin
我不明白如果我将代码包围在 Lock 中,怎么会有两个 begin 打印。有什么简单的方法可以保护代码块,所以理想情况下我得到:
10.txt begin
10.txt end
11.txt begin
11.txt end
20.txt begin
20.txt end

4

1 回答 1

5

threading.Lock仅适用于同一进程的线程之间。

在实际上不知道您在这里使用什么库进行并行处理的情况下,很难确定,但几乎可以肯定它是在单独的进程中执行任务。(任何在同一个进程中启动线程的东西,至少对于 CPython,都不会因为 GIL 而为 CPU 绑定代码获得任何有效的并行性。因此,他们都没有这样做。)

因此,如果您尝试使用threading.Lock来自其他进程的全局对象,您将在每个进程中获得一个完全独立的锁。所以,锁定它没有任何好处。(使用一些并行库——每个平台上可能不同——你会得到一个错误。但它不可能做你想做的事。)

大多数并行化库都有自己的锁类型,可以使用它们的多处理风格。如果是这样,请使用图书馆附带的那个。

如果没有,取决于您的图书馆的工作方式,multiprocessing.Lock可能会奏效。

如果没有,您将不得不使用例如锁定文件(可能与flock/一起lockf,或依赖于 Windows 独占打开或其他)来显式地实现某些东西。

另外,请注意,具有可以理解您的示例代码行的 API 的多个库中的至少一个 [ joblib] 是为没有任何共享的任务明确设计的,因此不应该与完全锁定。(它可能multiprocessing.Lock无论如何都可以使用,但你真的不应该指望它。)

于 2013-01-10T23:27:50.720 回答