C#からPythonへポインタ渡しするとは逆に、Python for .NETを使ってPythonからC#へポインタ渡しする方法について紹介する。
Python for .NET
Python for .NETを使用すると、PythonからC#のコードを呼び出すことができる。
Pythonと同じプロセスで、.NETのランタイムを動かすことができ、C#で記述したコードをPythonのモジュールと同じように扱うことができる。
import clr from System import String from System.Collections import *
C#側のコード作成
.NET Core 3.1を使用して、C#のコードを作成する。
クラスライブラリのプロジェクトを作成する。
dotnet new classlib --name torch_sharp
以下の通りC#のコードを記述する。
using System; namespace torch_sharp { public class Class1 { public unsafe void func(IntPtr data, int size) { float* array = (float*)data.ToPointer(); for (int i = 0; i < size; ++i) { array[i] = i; } } } }
Python側のコード作成
以下の通りPythonのコードを記述する。
import clr clr.AddReference('torch_sharp') from torch_sharp import Class1 from System import IntPtr import numpy as np obj = Class1() data = np.empty(5, dtype=np.float32) obj.func(IntPtr.op_Explicit(data.ctypes.data), len(data)) print(data)
解説
clr.AddReference('torch_sharp') from torch_sharp import Class1
この部分で、C#のクラスライブラリをPythonモジュールとしてimportしている。
ビルドしたC#の.dllファイルは、Pythonモジュールと同じディレクトリに配置しておく必要がある。
C#のプロジェクトファイル(.csproj)で、
<Target Name="CopyDLL" AfterTargets="AfterBuild"> <Copy SourceFiles="$(OutDir)/torch_sharp.dll" DestinationFolder="../../torch_sharp/" /> </Target>
のように記述しておくとよい。
Python側からC#にポインタ渡しするデータは、Numpyで作成する。
IntPtr.op_Explicit(data.ctypes.data)
の部分で、Numpyのデータをポインタとして取り出して、C#のIntPtr型に変換している。
ポインタを数値型のままC#に渡して、C#側でIntPtrにしてもよいが、IntPtrで渡した方が32bit、64bitかを気にしなくてよい。
まとめ
PythonからC#へポインタ渡しする方法について紹介した。
C#のアプリケーションで作成したデータを使って、Pythonでモデルを学習したいというようなケースで、C#のデータをシリアライズして、Python側で読み込みたいような場合に、PythonからC#のコードが呼べると便利である。
モデルに入力するためのデータの前処理を行うとデータ量が増えるため、シリアライズデータは加工前の状態にしたいが、Pythonで加工を行うと遅いため、速度を考慮するとC#で加工を行いたい。
しかし、PythonとC#の間で、データのマーシャリングが発生すると呼び出しのオーバーヘッドが発生するので、ここで紹介した方法でポインタ渡しをするとオーバーヘッドを抑えられる。