2011-07-16 18 views
8

Me gustaría implementar el código C# en una parte crítica de mi programa python para hacerlo más rápido. Se dice (en la documentación de Python y this site) que puede cargar una biblioteca de enlace dinámico (y por lo que dicen la PyDocs) de la siguiente manera:Usar ctypes en python para acceder a los métodos de un dll de C#

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

Esta es la parte de mi código que se encarga de esta función:

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

Y el RECERCATOOLS.dll que utilizo es este (código C#, no en C o 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; 
    } 
} 

Para construir esta DLL utilizo Comando "Build" sobre el proyecto de Visual Studio 2010, que solo contiene este archivo y una referencia a "Karlstools", un módulo que me permite usar números complejos.

No sé por qué, pero cuando trato de ejecutar mi código Python, sólo se produce una excepción:

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

Necesito ayuda con esto, ya que me mantiene lanzar excepciones, incluso con todo lo que se establece a public y la función como static, o incluso si intento acceder a la función directamente sin especificar la clase "Programa" ... No tengo idea de dónde podría estar el problema.

+0

[exportaciones no administrados] (https://sites.google .com/site/robertgiesecke/Home/uploads/unmanagedexports). [Exportación de código administrado como no administrado] (http://www.csharphelp.com/2007/03/exporting-managed-code-as-unmanaged) (2007). – eryksun

Respuesta

7

Los consejos que encontrará con respecto a llamar DLL desde Python utilizando ctypes dependen la mayor parte del tiempo para que la DLL se escriba en C o C++, no en C#. Con C#, usted aprovecha toda la maquinaria de la CLR, y es muy probable que los símbolos estén destrozados y no sean los que los tipos esperan, y obtendrá todo tipo de problemas de la recolección de basura de su matriz de salida.

He tenido muy buen éxito al conectar Python y el código C# utilizando python para dot net (http://pythonnet.sf.net), es posible que desee probar esto.

Por otro lado, si está buscando un rendimiento puro, considere reescribir su código como una extensión C nativa para Python usando la API de Python/C (http://docs.python.org/c-api/).

1

ctypes es para cargar bibliotecas compartidas escritas en C (o al menos bibliotecas compartidas que son ejecutables directamente por la CPU y exportar sus símbolos y argumentos de funciones siguiendo las convenciones estándar de C.) C# DLL no son DLL "normales", pero más bien pensado para ejecutarse en un entorno .NET.

Las opciones son:

  1. utilizar algún tipo de Python para el puente .NET.
  2. Escriba la DLL en C y use ctypes para llamar a la función y manejar las conversiones de datos.
  3. Utilice la API de Python/C y cree un módulo de Python cargable.

No puedo hablar con la opción n. ° 1, no lo he hecho. La opción n. ° 2 es, por lo general, más fácil que la opción n. ° 3, ya que se escribe código C puro y se pega con ctypes. La opción n. ° 3 ofrecerá el mejor rendimiento de las tres opciones, ya que tiene la sobrecarga de llamadas más baja y está ejecutando código nativo en el procesador.

3

Otros han señalado que una DLL C# no se puede tratar de la misma manera que una DLL nativa.

Una opción que tiene es exportar su funcionalidad de C# como un objeto COM que puede ser fácilmente consumido por Python.

Personalmente, consideraría una solución de código nativo, pero es posible que esté demasiado comprometido con C# para cambiar el rumbo en esta etapa.

1

A C# DLL realmente se conoce como un ensamblado, por lo que es bastante diferente. A menos que haya una razón muy importante, sugiero que utilice C++

7

En realidad, es bastante fácil. Simplemente use NuGet para agregar el paquete "UnmanagedExports" a su proyecto .Net. Vea https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports para más detalles.

Puede exportar directamente, sin tener que hacer una capa COM. Aquí está la muestra de código C#:

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

, puede cargar el archivo DLL y llamar a los métodos expuestos en Python (que funciona para 2.7)

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

En caso de que la biblioteca no pueda ejecutarse desde Python, pequeña sugerencia, "debe establecer el destino de su plataforma en x86, ia64 o x64. Los ensamblados de CPU no pueden exportar funciones". –

Cuestiones relacionadas