簡體   English   中英

在多線程程序中同步嵌入式Python

[英]Synchronizing embedded Python in multi-threaded program

以下是在多線程程序中使用Python解釋器的示例:

#include <python.h>
#include <boost/thread.hpp>

void f(const char* code)
{
    static volatile auto counter = 0;
    for(; counter < 20; ++counter)
    {
        auto state = PyGILState_Ensure();
        PyRun_SimpleString(code);
        PyGILState_Release(state);

        boost::this_thread::yield();
    }
}

int main()
{
    PyEval_InitThreads();
    Py_Initialize();
    PyRun_SimpleString("x = 0\n");
    auto mainstate = PyEval_SaveThread();

    auto thread1 = boost::thread(f, "print('thread #1, x =', x)\nx += 1\n");
    auto thread2 = boost::thread(f, "print('thread #2, x =', x)\nx += 1\n");
    thread1.join();
    thread2.join();

    PyEval_RestoreThread(mainstate);
    Py_Finalize();
}

它看起來很好,但它沒有同步。 Python解釋器在PyRun_SimpleString期間多次釋放並重新獲取GIL(參見docs,p。#2 )。

我們可以使用我們自己的同步對象來序列化PyRun_SimpleString調用,但這是一種錯誤的方法。

Python有自己的同步模塊_threadthreading 但它們不適用於此代碼:

Py_Initialize();
PyRun_SimpleString(R"(
import _thread
sync = _thread.allocate_lock()

x = 0
)");

auto mainstate = PyEval_SaveThread();

auto thread1 = boost::thread(f, R"(
with sync:
    print('thread #1, x =', x)
    x += 1
)");
  • 它產生錯誤File "<string>", line 3, in <module> NameError: name '_[1]' is not defined和死鎖。

如何同步嵌入式python代碼最有效的方法?

當CPython調用可能阻塞(或重新輸入Python)的函數時,它會在調用函數之前釋放全局解釋器鎖,然后在函數返回后重新獲取鎖。 在您的代碼中,您調用內置的print函數會導致釋放解釋器鎖並運行另一個線程(請參閱string_print中的string_print )。

所以你需要自己的鎖:全局解釋器鎖不適合確保執行I / O的Python代碼的序列化。

由於您正在使用Boost線程框架,因此您可能不會發現使用Boost 線程同步原語之一最方便,例如boost::interprocess::interprocess_mutex

[編輯:我的原始答案是錯誤的,正如Abyx指出的那樣。]

with語句在Python 3.1中有問題 ,但它在Python 3.2和Python 2.7中得到修復。

因此,正確的解決方案是使用threading模塊進行同步。

為了避免這樣的問題,不應該使用在globals字典中使用臨時變量的多線程代碼,或者為每個線程使用不同的全局字典。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM