1 回答

TA貢獻2003條經驗 獲得超2個贊
目前的問題是該變量singleton
存在兩次:一次在擴展中setter
,一次在擴展中getter
(也可以運行get_singleton
并set_singleton
存在兩次,即每個有兩個不同的地址),這或多或少違反了一個定義規則(ODR),甚至如果這個規則只存在于C++中。違反 ODR 并不是世界末日,但在大多數情況下,該行為變得不可移植,因為不同的鏈接器/編譯器/操作系統以不同的方式處理這種情況。
例如,對于 Linux 上的共享庫,我們有符號插入。然而,Python 使用ldopen
without?RTLD_GLOBAL
(隱含 with?RTLD_LOCAL
)來加載 C 擴展,從而防止符號插入。我們可以在 Python 中強制使用RTLD_GLOBAL
:
import?sys;?import?ctypes; sys.setdlopenflags(sys.getdlopenflags()?|?ctypes.RTLD_GLOBAL)
getter
在導入并setter
再次恢復單例屬性之前。然而,這在 Windows 上不起作用,因為 dll 不支持符號插入。
確?!皢卫龑傩浴钡目梢浦卜椒ㄊ潜苊膺`反 ODR,并且為了實現這一點,應該使靜態庫/文件束動態化。該動態庫只會被進程加載一次,從而確保我們只有一個singleton
.
根據具體情況,可以選擇如何使用此 dll:
這些擴展僅在本地使用,而不是使用共享對象
擴展僅分布在某些平臺上,那么可以預構建共享對象/dll 并像第三方庫一樣分布它們,例如參見此 SO-?post
可以覆蓋setuptools的
build_clib
命令,因此它將構建一個共享對象/dll而不是靜態庫,當擴展被鏈接并復制到安裝時將使用該庫。然而,添加更多的擴展,這將使用這個 dll 是相當麻煩的(即使不是不可能)。可以編寫 dll 的 cython 包裝器,它的優點是使用 Python 的機制來加載和推遲符號的結果直到運行時,而不是底層操作系統的鏈接器/加載器,這使得例如,稍后可以更輕松地根據動態庫創建進一步的擴展。
我認為默認情況下應該使用最后一種方法。這是一個可能的實現:
創建靜態庫的包裝并通過
pxd
-file 公開其功能:
# lib_wrapper.pxd
cdef int get_singleton()
cdef void set_singleton(int new_value)
#lib_wrapper.pyx
cdef extern from "lib.h":
? ? int c_get_singleton "get_singleton" ()
? ? void c_set_singleton "set_singleton" (int new_val)
cdef int get_singleton():
? ? return c_get_singleton()
cdef void set_singleton(int new_val):
? ? c_set_singleton(new_val)
一個重要的部分是:包裝器引入了一定程度的間接性(從而導致大量應該自動化的樣板代碼編寫),因此當在其他模塊中使用它時,既不需要頭文件也不需要 c 文件/庫。
調整其他模塊,它們只需要cimport包裝器:
# getter.pyx:
#cython: language_level=3
cimport lib_wrapper
def get():
? ? return lib_wrapper.get_singleton()
# setter.pyx:
#cython: language_level=3
cimport lib_wrapper
def set(new_val):
? ? lib_wrapper.set_singleton(new_val)
安裝程序不再需要build_clib-step:
from setuptools import setup, find_packages, Extension
setup(
? ? ? name='singleton_example',
? ? ? ext_modules=[Extension('lib_wrapper', sources=['lib_wrapper.pyx', 'lib.c']),
? ? ? ? ? ? ? ? ? ?Extension('getter', sources=['getter.pyx']),?
? ? ? ? ? ? ? ? ? ?Extension('setter', sources=['setter.pyx']),],
? ? ?)
構建 via 后python setup.py build_ext --inplace(在源代碼分發中,即python setup.py build sdisth 文件將丟失,但對于此問題可能有許多不同的解決方案),示例將set/get相同的單例(因為只有一個)。
添加回答
舉報