2011-07-16 10 views
8

pythonプログラムの重要な部分にC#コードを実装してより速くしたいと考えています。Pythonでctypesを使用してC#dllのメソッドにアクセスする

cdll.LoadLibrary("your-dll-goes-here.dll")

これは、この機能の世話をする私のコードの一部です:それは次のように(PyDocsをしてそう言う)ダイナミックリンクライブラリをロードすることができます(Pythonドキュメントとthis siteに)書かれています:私が使用することを

from ctypes import * 
z = [0.0,0.0] 
c = [LEFT+x*(RIGHT-LEFT)/self.size, UP+y*(DOWN-UP)/self.size] 
M = 2.0 

iterator = cdll.LoadLibrary("RECERCATOOLS.dll") 

array_result = iterator.Program.ITERATE(z[0],z[1],c[0],c[1],self.iterations,M) 

z = complex(array_result[0],array_result[1]) 
c = complex(array_result[2],array_result[3]) 
last_iteration = int(round(array_result[4])) 

そしてRECERCATOOLS.dllこの(C#のコードではなく、CまたはC++)である:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using KarlsTools; 

public class Program 
{ 
    public static Array ITERATE(double z_r,double z_i,double c_r, 
         double c_i, int iterations, 
         double limit) 
    { 
     Complex z = new Complex(z_r, z_i); 
     Complex c = new Complex(c_r, c_i); 

     for (double i = 1; Math.Round(i) <= iterations; i++) 
     { 
      z = Complex.Pow(z, 2) + c; 
      if (Complex.Abs(z) < limit) 
      { 
       double[] numbers = new double[] { Complex.Real(z), 
                Complex.Imag(z), 
                Complex.Real(c), 
                Complex.Imag(c), 
                i}; 
       return numbers; 
      } 
     } 
     double iter = iterations; 
     double[] result = new double[]  { Complex.Real(z), 
                Complex.Imag(z), 
                Complex.Real(c), 
                Complex.Imag(c), 
                iter}; 
     return result; 
    } 
} 

私が使用して、このDLLをビルドするには"ビルド"コマンドは、このファイルと、複素数を使用できるモジュールである "Karlstools"への参照のみを含むVisual Studio 2010プロジェクトに適用されます。

私はなぜ知らないが、私は私のPythonコードを実行しようとすると、それだけで例外をスロー:

[...] 
    array_result = iterator.Program.ITERATE(z[0],z[1],c[0],c[1],self.iterations,M) 
    File "C:\Python32\lib\ctypes\__init__.py", line 353, in __getattr__ 
    func = self.__getitem__(name) 
    File "C:\Python32\lib\ctypes\__init__.py", line 358, in __getitem__ 
    func = self._FuncPtr((name_or_ordinal, self)) 
AttributeError: function 'Program' not found 

それはすべてが設定されていてもしてくれ例外をスローし続けるので、私は、これで助けを必要とpublicに、staticのように機能するか、「プログラム」クラスを指定せずに関数に直接アクセスしようとしても、問題がどこにあるのか分かりません。

+0

:ここではサンプルのC#コードであります.com/site/robertgiesecke/Home/uploads/unmanagedexports)。 [マネージコードをアンマネージドとしてエクスポートする](http://www.csharphelp.com/2007/03/exporting-managed-code-as-unmanaged)(2007) – eryksun

答えて

7

ctypesを使用してPythonからDLLを呼び出す際のヒントは、CまたはCではなく、CまたはC++で記述されたDLLにほとんど依存しています。 C#では、CLRの機械全体を引っ張り出します。シンボルはおそらく、どのタイプのものであろうとよく分からなくなります。出力配列のガベージコレクションからあらゆる種類の問題が発生します。

pythonとドットネット(http://pythonnet.sf.net)を使用してC#コードをインターフェイスするときに非常にうまくいっていますが、これを試してみるとよいでしょう。

一方、純粋なパフォーマンスの場合は、Python/C API(http://docs.python.org/c-api/)を使用して、コードをPythonのネイティブC拡張として書き直すことを検討してください。

1

​​は、Cで書かれた共有ライブラリ(またはCPUによって直接実行可能な共有ライブラリをロードし、標準のC規則に従ってシンボルと関数の引数をエクスポートします)。C#DLLは「通常の」DLLではなくむしろ.NET環境で実行することを意図しています。

あなたのオプションは以下のとおりです。

  1. .NETブリッジへのPythonのいくつかの並べ替えを使用してください。
  2. DLLをC言語で記述し、​​を使用して関数を呼び出し、データ変換を処理します。
  3. Python/C APIを使用して、読み込み可能なPythonモジュールを作成します。

私はオプション1と話すことができません。私はそれをしていません。オプション#2は、純粋なCコードを書いてそれを​​で接着するという点で、オプション#3より簡単です。オプション3は、コールオーバーヘッドが最も低く、プロセッサ上でネイティブコードを実行しているという点で、3つのオプションの中で最高のパフォーマンスを提供します。

3

他の人は、C#DLLはネイティブDLLと同じ方法で扱うことができないと指摘しています。

あなたが持っている選択肢の1つは、C#の機能をCOMオブジェクトとしてエクスポートすることです。これはPythonで簡単に使用できます。

私はネイティブコードソリューションを個人的に考えていますが、この段階でコースを変更するにはC#にもコミットしている可能性があります。

1

C#DLLは実際にはアセンブリと呼ばれているため、全く異なります。 非常に重要な理由がない限り、私はあなたにC++を使うことをお勧めします。

7

実際にはかなり簡単です。 NuGetを使って.Netプロジェクトに "UnmanagedExports"パッケージを追加するだけです。詳細は、https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexportsを参照してください。

これで、COMレイヤーを使わずに直接エクスポートできます。 [管理されていない輸出](https://sites.googleは、あなたがそれからDLLをロードし、Pythonで公開されたメソッドを呼び出すことができます

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Threading.Tasks; 
using RGiesecke.DllExport; 

class Test 
{ 
    [DllExport("add", CallingConvention = CallingConvention.Cdecl)] 
    public static int TestExport(int left, int right) 
    { 
     return left + right; 
    } 
} 

(2.7のために働く)

import ctypes 
a = ctypes.cdll.LoadLibrary(source) 
a.add(3, 5) 
+0

ライブラリをPythonから実行できない場合 - 小さなヒント - "プラットフォームターゲットをx86、ia64、またはx64に設定する必要があります。AnyCPUアセンブリは関数をエクスポートできません。" –

関連する問題