python pint模块实现物理量。我想将它与多处理一起使用。但是,我不知道如何处理在新进程中创建UnitRegistry。如果我做直观的话:
from multiprocessing import Process
from pint import UnitRegistry, set_application_registry
ureg = UnitRegistry()
set_application_registry(ureg)
Q = ureg.Quantity
def f(one, two):
print(one / two)
if __name__ == '__main__':
p = Process(target=f, args=(Q(50, 'ms'), Q(50, 'ns')))
p.start()
p.join()
然后我得到以下异常:
Traceback (most recent call last):
File "C:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\multiprocessing\process.py", line 254, in _bootstrap
self.run()
File "C:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\multiprocessing\process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\pmaunz\PyCharmProjects\IonControl34\tests\pintmultiprocessing.py", line 12, in f
print(one / two)
File "C:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\site-packages\pint\quantity.py", line 738, in __truediv__
return self._mul_div(other, operator.truediv)
File "C:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\site-packages\pint\quantity.py", line 675, in _mul_div
offset_units_self = self._get_non_multiplicative_units()
File "C:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\site-packages\pint\quantity.py", line 1312, in _get_non_multiplicative_units
offset_units = [unit for unit in self._units.keys()
File "C:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\site-packages\pint\quantity.py", line 1313, in <listcomp>
if not self._REGISTRY._units[unit].is_multiplicative]
KeyError: 'millisecond'
我认为这是因为在取消参数之前,缺少在子进程上初始化UnitRegistry。 (在函数f中初始化UnitRegistry不起作用,因为变量已经被打开了。)
我如何向儿童流程发送品脱数量?
蒂姆彼得的回答后编辑:
问题是不与多处理相关联。简单的酸洗量
from pint import UnitRegistry, set_application_registry
import pickle
ureg = UnitRegistry()
set_application_registry(ureg)
Q = ureg.Quantity
with open("pint.pkl", 'wb') as f:
pickle.dump(Q(50, 'ms'), f)
pickle.dump(Q(50, 'ns'), f)
然后在 new 脚本中进行unpickling会导致同样的问题:
from pint import UnitRegistry, set_application_registry
import pickle
ureg = UnitRegistry()
set_application_registry(ureg)
Q = ureg.Quantity
with open("pint.pkl", 'rb') as f:
t1 = pickle.load(f)
t2 = pickle.load(f)
print(t1 / t2)
导致相同的异常。正如蒂姆指出的那样,在展开前添加一行Q(50, 'ns'); Q(50, 'ms')
就足够了。在深入了解pint的源代码时,在创建单位为ms
的数量时,此单位将添加到内部注册表中。 Pickling使用UnitContainer
实例来保存单位。通过unpickling创建数量时, not 已添加到注册表中。
一个简单的修复(在品脱源代码中)是更改函数Quantity.__reduce__
以返回一个字符串。
diff --git a/pint/quantity.py b/pint/quantity.py
index 3f30a25..695866a 100644
--- a/pint/quantity.py
+++ b/pint/quantity.py
@@ -57,7 +57,7 @@ class _Quantity(SharedRegistryObject):
def __reduce__(self):
from . import _build_quantity
- return _build_quantity, (self.magnitude, self._units)
+ return _build_quantity, (self.magnitude, str(self._units))
def __new__(cls, value, units=None):
if units is None:
我在pint的github网站上打开了一个问题。
答案 0 :(得分:1)
我之前从未使用pint
,但这看起来很有趣;-)我注意到的第一件事是,如果我坚持使用此行明确列出的单位,我没有问题:
print(dir(ureg.sys.mks))
例如,“hour”和“second”都在其输出中,如果Process
行更改为:
p = Process(target=f, args=(Q(50, 'hour'), Q(50, 'second')))
你在Windows上,所以multiprocessing
正在使用“spawn”方法:整个程序是由工作进程新导入的,所以特别是:
ureg = UnitRegistry()
set_application_registry(ureg)
Q = ureg.Quantity
行也在工作进程中执行。因此单元注册表在工作程序中初始化,但它与主程序中使用的注册表不同(相同) - 进程之间不共享内存。
为了更深入,我们真的需要一位专家来实现pint
。我的猜测是,对于单位“组成”(不是在上面的dir()
行产生的输出中)通过解析字符串,新的东西会在某个级别添加到注册表中,稍后需要重新构建值。 “ns”和“ms”具有这种性质:它们在dir()
输出中不。
你的程序可以正常运行如果我会在Q=ureg.Quantity
行之后立即添加这样的一行:
Q(1, 'ms'); Q(1, 'ns')
这是一个黑暗的镜头(一个“有根据的猜测”),它起作用:它只是强迫工人进程解析主进程中使用的相同“组成”单位,试图强制其< / em>单元注册表进入类似的状态。
我希望有更清洁的方式让它发挥作用,但无法提供更多帮助。我会问pint
作者。