2011-07-16 13 views
8

Tôi muốn triển khai mã C# trong phần quan trọng của chương trình python của tôi để làm cho nó nhanh hơn. Nó nói (trên giấy tờ Python và this site) mà bạn có thể tải một Dynamic Link Library (và do đó nói PyDocs) như sau:Sử dụng ctypes trong python để truy cập các phương thức của C# dll

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

Đây là một phần của mã của tôi rằng sẽ chăm sóc của tính năng này:

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])) 

Và RECERCATOOLS.dll mà tôi sử dụng là này (code C#, không phải C hay 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; 
    } 
} 

xây dựng DLL này tôi sử dụng Lệnh "Xây dựng" trên dự án Visual Studio 2010, chỉ chứa tệp này và tham chiếu đến "Karlstools", một mô-đun cho phép tôi sử dụng các số phức.

Tôi không biết tại sao nhưng khi tôi cố gắng để chạy mã Python của tôi, nó chỉ ném một ngoại lệ:

[...] 
    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 

Tôi cần giúp đỡ với điều này, vì nó giữ ném cho tôi trường hợp ngoại lệ ngay cả với tất cả mọi thứ được thiết lập đến public và chức năng là static hoặc thậm chí khi tôi cố gắng truy cập trực tiếp vào chức năng mà không chỉ định lớp "Chương trình" ... Tôi không có đầu mối nào có thể xảy ra sự cố.

+0

[Switch Xuất khẩu] (https://sites.google .com/site/robertgiesecke/Home/uploads/unmanagedexports). [Xuất mã được quản lý là Không được quản lý] (http://www.csharphelp.com/2007/03/exporting-managed-code-as-unmanaged) (2007). – eryksun

Trả lời

7

Các mẹo bạn sẽ tìm thấy liên quan đến việc gọi DLL từ Python bằng cách sử dụng ctypes dựa phần lớn thời gian vào DLL được viết bằng C hoặc C++, chứ không phải C#. Với C# bạn kéo toàn bộ máy móc của CLR, và các biểu tượng có nhiều khả năng bị xáo trộn và không phải những gì ctypes mong đợi, và bạn sẽ nhận được tất cả các loại rắc rối từ bộ sưu tập rác của mảng đầu ra của bạn.

Tôi đã có thành công rất tốt khi giao tiếp mã python và C# bằng cách sử dụng python cho dot net (http://pythonnet.sf.net), bạn có thể muốn thử điều này.

Mặt khác, nếu bạn đang ở hiệu suất thuần túy, hãy xem xét viết lại mã của bạn dưới dạng phần mở rộng C gốc cho Python bằng cách sử dụng API Python/C (http://docs.python.org/c-api/).

1

ctypes là để tải thư viện chia sẻ được viết bằng C (hoặc ít nhất các thư viện được thực thi trực tiếp bởi CPU và xuất các ký hiệu và đối số hàm của chúng theo các quy ước C chuẩn.) C# DLLs không phải là "bình thường" DLL, nhưng thay vì định chạy trong môi trường .NET.

lựa chọn của bạn là:

  1. Sử dụng một số loại Python để NET cầu.
  2. Viết DLL trong C và sử dụng ctypes để gọi hàm và xử lý các chuyển đổi dữ liệu.
  3. Sử dụng API Python/C và tạo mô-đun Python có thể tải.

Tôi không thể nói với tùy chọn # 1, tôi chưa thực hiện. Tùy chọn # 2 thường dễ hơn lựa chọn # 3 trong đó bạn viết mã C thuần túy và dán nó vào với ctypes. Tùy chọn # 3 sẽ cung cấp hiệu suất tốt nhất của cả ba tùy chọn ở chỗ nó có chi phí cuộc gọi thấp nhất và đang chạy mã gốc trên bộ xử lý.

3

Những người khác đã chỉ ra rằng một C# DLL không thể được xử lý theo cùng một cách như một DLL gốc.

Một tùy chọn bạn có là xuất chức năng C# của bạn dưới dạng đối tượng COM có thể dễ dàng sử dụng bởi Python.

Cá nhân tôi muốn xem xét giải pháp mã gốc nhưng bạn cũng có thể quá cam kết với C# để thay đổi khóa học ở giai đoạn này.

1

Một C# DLL thực sự được gọi là một hội để nó hoàn toàn khác. Trừ khi có một lý do rất quan trọng tôi đề nghị bạn sử dụng C++

7

Nó thực sự là khá dễ dàng. Chỉ cần sử dụng NuGet để thêm gói "UnmanagedExports" vào dự án .Net của bạn. Xem https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports để biết chi tiết.

Sau đó, bạn có thể xuất trực tiếp mà không phải thực hiện lớp COM. Dưới đây là các mẫu C# code:

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; 
    } 
} 

Sau đó bạn có thể tải dll và gọi các phương pháp tiếp xúc bằng Python (chỉ hoạt động cho 2,7)

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

Trong trường hợp thư viện không thể được thực hiện từ Python - gợi ý nhỏ - "Bạn phải đặt mục tiêu nền tảng của bạn thành x86, ia64 hoặc x64. Không thể xuất các hàm của AnyCPU." –