2016-07-17 34 views
2

python品脫模塊實現物理量。我想與多處理一起使用它。但是,我不知道如何處理在新流程中創建UnitRegistry。如果我做了直觀的:具有多處理功能的Python品脫模塊

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) 

,然後在腳本取儲存導致了同樣的問題:

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) 

導致相同的異常。正如Tim指出的那樣,在取出前添加一行Q(50, 'ns'); Q(50, 'ms')就足夠了。在深入挖掘pint的源代碼時,在單位ms創建數量時,將該單元添加到內部註冊表中。酸洗使用UnitContainer實例來保存單位。通過取消打印創建數量時,該單位是而不是添加到註冊表中。

一個簡單的修復(在品脫源代碼)是改變功能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

Bravo!這一切都很有意義。我感到驚訝的是,之前沒有人遇到過這種情況 - 在一個過程中進行酸洗,而在另一個過程中進行酸洗就是使用泡菜的方式(即使沒有「多重處理」)! –

回答

1

我從來沒有使用過pint前,但是這看起來我注意到有趣的;-)的第一件事是,我有沒有問題,如果我堅持要通過這條線明確列出單位:

print(dir(ureg.sys.mks)) 

例如,「小時「和‘第二’都在那輸出,而如果Process線更改爲你的程序運行良好:

p = Process(target=f, args=(Q(50, 'hour'), Q(50, 'second'))) 

您使用的是Windows,所以multiprocessing使用‘重生’法:整個程序是由新進口的工作進程,特別是:

ureg = UnitRegistry() 
set_application_registry(ureg) 
Q = ureg.Quantity 

行也在工作進程中執行。因此,單元註冊表在工作人員中初始化了,但它與主程序中使用的不一樣(相同)註冊表 - 在進程之間沒有共享內存。

爲了更深入地研究,我們確實需要一個專家來實現pint。我的猜測是,通過解析字符串,對於「組成」單元(不在上面dir()行生成的輸出中),新的東西被添加到註冊表的某個級別,稍後需要重新創建值。 「ns」和「ms」具有這種性質:它們是而不是dir()輸出中。

你的程序工作正常原樣如果我你Q=ureg.Quantity行後立即加入這樣一行:

Q(1, 'ms'); Q(1, 'ns') 

那是在黑暗的起作用(一個「的猜測」)一拍:它只是迫使工作進程解析主進程中使用的相同「組成」單元,嘗試強制其單元註冊表處於類似狀態。

我希望有一個更清晰的方式來讓它工作,但不能幫助更多。我會問pint作者。