2016-03-29 47 views
1

私のCコードからPython関数を呼び出す必要があります。 これは完璧に動作しますが、並列化をしたいときは分解します。あなたは​​でそれをコンパイルすることができ、testPython.cとしてPythonをCから並列に呼び出す

#include <Python.h> 
#include <stdio.h> 

int main(void) 
{ 
    double Z = 1.; 
    double k = 1.; 
    double l = 1.; 
    double eta = -Z/k; 

    Py_Initialize(); 

    PyObject* pName = PyString_FromString("mpmath"); 
    PyObject* pModule = PyImport_Import(pName); 
    PyObject* pFunc = PyObject_GetAttrString(pModule, "coulombf"); 

    PyObject* pl = PyFloat_FromDouble(l); 
    PyObject* peta = PyFloat_FromDouble(eta); 

    int i; 
#pragma omp parallel for private(i) 
    for(i=0; i<10000; i++) 
    { 
    double r = 0.01*i; 
    PyObject* prho = PyFloat_FromDouble(k*r); 
    PyObject* pArgs = PyTuple_Pack(3, pl, peta, prho); 
    PyObject* pValue = PyObject_CallObject(pFunc, pArgs); 
    double value = PyFloat_AsDouble(pValue); 
    printf("r=%.2f\tf=%.6f\n",r,value); 
    } 

    Py_Finalize(); 
    return 0; 
} 

レッツ・名前このファイル: には、以下の最小限のCコードを参照してください。

./testPythonで実行すると、このようなエラーが表示されます。Fatal Python error: GC object already tracked (場合によっては、エラー情報が異なります)

しかし、コンパイルして-fopenmpを残しておけば、プログラムは完全に動作します。

どうすればこの問題を解決できますか?ありがとう!

編集:Natecat、ジョン・ボリンジャー、およびオラフで答えたよう

、マルチスレッドは、多くのプロセスをスピードアップすることはほとんどありませんが、マルチプロセッシングは本当に計算をスピードアップすることができます。純粋なpythonスクリプトは次のように簡単です:

import numpy 
from mpmath import coulombf 
from multiprocessing import Pool 

Z = 1. 
k = 1. 
l = 1. 
eta = -Z/k 

def coulombF(r): 
    return coulombf(l,eta,k*r) 

pool = Pool(12) 
result = pool.map_async(coulombF, numpy.arange(0.,100.,0.01)) 
print(result.get()) 

しかし、私はどのようにCでそれをしますか?私はまだ方法を見つけていない。

+0

明確にするために、これはプロセスではなく別のスレッドを作成しようとしていますか? – Natecat

+0

はい、OpenMPを使用して別々のスレッドを作成し、各スレッドはPython関数を呼び出します。 –

答えて

3

@ Natecatの回答は基本的に正しいですが、細部とニュアンスが欠けています。 The docs of Python's C APIより完全な画像を提供します。これは、使用しているPython実装であるとすると、次の点に注意する必要があります

The Python interpreter is not fully thread-safe. In order to support multi-threaded Python programs, there’s a global lock, called the global interpreter lock or GIL, that must be held by the current thread before it can safely access Python objects. Without the lock, even the simplest operations could cause problems in a multi-threaded program [...].

Therefore, the rule exists that only the thread that has acquired the GIL may operate on Python objects or call Python/C API functions. In order to emulate concurrency of execution, the interpreter regularly tries to switch threads (see sys.setswitchinterval()). The lock is also released around potentially blocking I/O operations like reading or writing a file, so that other Python threads can run in the meantime.

when threads are created from C (for example by a third-party library with its own thread management), they don’t hold the GIL, nor is there a thread state structure for them.

注:これはまさにOpenMPの場合です。

If you need to call Python code from these threads [...] you must first register these threads with the interpreter by creating a thread state data structure, then acquiring the GIL, and finally storing their thread state pointer, before you can start using the Python/C API. When you are done, you should reset the thread state pointer, release the GIL, and finally free the thread state data structure.

The PyGILState_Ensure() and PyGILState_Release() functions do all of the above automatically. The typical idiom for calling into Python from a C thread is:

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 

/* Perform Python actions here. */ 
result = CallSomeFunction(); 
/* evaluate result or handle exception */ 

/* Release the thread. No Python API allowed beyond this point. */ 
PyGILState_Release(gstate); 

あなた同じCPythonのインタプリタへの同時呼び出しを行うために、安全に、複数のOpenMPスレッドを許可するように、そのパターンを実装する必要がありますが、様々なOpenMPのスレッドが大きくなりますよう、あなたは、並列化から多くの利益を得る可能性は低いです同時に実行することができませんでした。

+0

実際、あなたの答えは非常に良い可能性があることを示しています。実際の問題は、アプリケーションがそのメリットを享受できるかどうかです。 I/Oが重いアプリケーションの場合、または1つまたは少数の処理スレッドと複数のIOスレッドを使用する場合は、これが適しています。 – Olaf

+0

これは並列化の目的を破って、一度に1つのスレッドにPythonコードを制限しないでしょうか? – Natecat

+0

@ Natecat、私が答えて書いたように、「さまざまなOpenMPスレッドが並行して実行されることはほとんどないので、並列化のメリットはあまりありません。しかし、一度に1つのPythonスレッドしか持たないのと全く同じことではありません。インタプリタはスレッド間で切り替わり、I/Oやその他の操作中に並行性を持つことができます。このような操作が少ない場合、私がここにあると推測しているように、有効な並行性は低いです。ただし、そのような操作が長時間または長時間行われると、効果的な並行性が高くなる可能性があります。 –

1

真のマルチスレッド(一プロセスに複数のシステムスレッドを使用するE.G.)は、少なくとも最も一般的なPythonの実装では不可能です。任意のパラレル化を使用することも、GILなしで実装に切り替えることもできます。ここでは、件名に関する詳細情報を持つ記事です:https://wiki.python.org/moin/GlobalInterpreterLock

+0

これは間違っています。 'threading'と' multiprocessing'モジュールを参照してください。 GILは実際にはインタプリタで内部競合のないマルチプロセッシングを可能にするために存在します。 – Olaf

+1

スレッド化では、シミュレートされた並行性のみが可能で、真のマルチスレッド化は起こっていません。マルチプロセッシングはマルチスレッドではなく、はるかに大きなオーバーヘッドを持ちます。これを明確にするために私の答えを変えてみよう – Natecat

+0

それはある種のマルチスレッドです。スレッドは、別々のプロセスである必要はありません。 – Olaf

関連する問題