我在Jupyter 5上使用Python 3.6.1。我的目标是测试portalocker如何管理同一文件上的并发追加。
为了实现这一点,我创建了一个简单的函数,将一行附加到同一个文件中,并使用multiprocessing.Pool和Pool.map()并行运行该函数。
以下是Jupyter笔记本中的代码。
细胞1
from time import time
from multiprocessing import Pool
import portalocker
def f(*args):
while time() < start + 1:
pass
with open('portalocker_test.txt', 'a') as f:
portalocker.lock(f, portalocker.LOCK_EX)
f.write(f'{time()}\n')
细胞2
start = time()
with Pool(4) as p:
p.map(f, range(4))
细胞3
with open('portalocker_test.txt', 'r') as f:
for line in f:
print(line, end='')
如果我在获得预期结果后运行此代码:
单元格3:
1495614277.189394
1495614277.1893928
1495614277.1893911
1495614277.1894028
但是如果我再次运行单元格2(没有重新启动笔记本),我得到:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-db9c07d32724> in <module>()
1 start = time()
2 with Pool(4) as p:
----> 3 p.map(f, range(4))
/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py in map(self, func, iterable, chunksize)
258 in a list that is returned.
259 '''
--> 260 return self._map_async(func, iterable, mapstar, chunksize).get()
261
262 def starmap(self, func, iterable, chunksize=None):
/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py in get(self, timeout)
606 return self._value
607 else:
--> 608 raise self._value
609
610 def _set(self, i, obj):
/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py in _handle_tasks(taskqueue, put, outqueue, pool, cache)
383 break
384 try:
--> 385 put(task)
386 except Exception as e:
387 job, ind = task[:2]
/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/connection.py in send(self, obj)
204 self._check_closed()
205 self._check_writable()
--> 206 self._send_bytes(_ForkingPickler.dumps(obj))
207
208 def recv_bytes(self, maxlength=None):
/Users/xxx/Homebrew/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/reduction.py in dumps(cls, obj, protocol)
49 def dumps(cls, obj, protocol=None):
50 buf = io.BytesIO()
---> 51 cls(buf, protocol).dump(obj)
52 return buf.getbuffer()
53
TypeError: cannot serialize '_io.TextIOWrapper' object
如果我在运行单元格2之前读取文件,则会引发相同的错误。因此,如果我在运行单元格2之前从未打开文件,则一切顺利。如果我之前打开文件,那么我会收到该错误。 这对我很不一致。到底是怎么回事?怎么解决?
此外,使用或不使用portalocker不会改变此行为,因此它不是portalocker的问题。我没有在普通的python上检查它,但我真的很想用Jupyter运行它。
答案 0 :(得分:5)
问题是你应该为不同的对象避免使用相同的名称,在你的情况下应该帮助
将功能名称从f
更改为function
(或其他名称与f
不同)
细胞1
from time import time
from multiprocessing import Pool
import portalocker
def function(*args):
while time() < start + 1:
pass
with open('portalocker_test.txt', 'a') as f:
portalocker.lock(f, portalocker.LOCK_EX)
f.write(f'{time()}\n')
细胞2
start = time()
with Pool(4) as p:
p.map(function, range(4))
或
将open
从f
获取的文件对象重命名为file
(或其他名称与f
不同):
细胞1
from time import time
from multiprocessing import Pool
import portalocker
def f(*args):
while time() < start + 1:
pass
with open('portalocker_test.txt', 'a') as file:
portalocker.lock(file, portalocker.LOCK_EX)
file.write(f'{time()}\n')
细胞3
with open('portalocker_test.txt', 'r') as file:
for line in file:
print(line, end='')
或两者
答案 1 :(得分:0)
我有类似的问题。就我而言,多重处理(例如:来自多重处理导入过程)与内存映射文件(导入mmap)之间存在冲突。删除了与内存映射文件有关的代码后,一切正常。
答案 2 :(得分:0)
我也有类似的问题:在我的例子中,一个类持有一个对(不可picklable)文件句柄的引用(即成员变量)。一旦我在工作完成后清除它(即设置为无),多处理工作正常。
在我的案例中的错误如下所示:
multiprocessing.pool.MaybeEncodingError: Error sending result: '[<backtest.StrategyBacktest object at 0x7efcd7eb6128>]'. Reason: 'TypeError("cannot serialize '_io.TextIOWrapper' object",)'