Maison  >  Article  >  développement back-end  >  Introduction détaillée à l'appel entre Python et C

Introduction détaillée à l'appel entre Python et C

零下一度
零下一度original
2017-07-16 12:03:481721parcourir

Bien que Python soit très efficace en développement, en tant que langage de script, ses performances ne sont pas élevées. Par conséquent, afin de prendre en compte à la fois l'efficacité et les performances du développement, les modules ayant des exigences de performances élevées sont généralement implémentés en C ou C++ ou exécutés. scripts python en c ou c++. Pour gérer la logique, le premier est généralement l'implémentation de certains modules en python, et le second est plus courant dans les programmes côté serveur (implémentant une expansion commerciale ou des fonctions de plug-in) et le développement de jeux (scripts uniquement). gérer la logique). Cet article présente principalement comment réaliser des appels mutuels entre python et c en exécutant des scripts python en c, et utilise l'exemple de définition de la même zone mémoire dans les scripts c et python.

Avant-propos

Récemment, en raison de besoins professionnels, j'envisage de créer un protocole de synchronisation de données basé sur udp pour les batailles de jeux en ligne pour des tests préliminaires Pour les données, nous avons décidé de créer d'abord un tunnel proxy externe. Le principe est d'établir des proxys de transfert de réseau respectivement côté serveur et côté client, c'est-à-dire que la connexion C/S d'origine est remplacée par une transmission rapide des données entre les deux proxys. . Parce que la bibliothèque udp est du code écrit en C++, il est très ennuyeux de modifier constamment les paramètres, de recompiler, de modifier les données statistiques de sortie et de tabuler lors du test des données. Enfin, il a été décidé d'utiliser un script python pour effectuer des appels logiques vers l'interface d'exportation. Pas grand chose à dire ci-dessous, jetons un œil à l'introduction détaillée :

Travail de préparation

Afin d'exécuter un script python en c, vous devez ajouter python lors de la liaison du programme, la bibliothèque de la machine virtuelle est liée. La bibliothèque de la machine virtuelle python est le fichier python27.lib dans les bibliothèques du répertoire d'installation de python. Quant à la façon de lier la bibliothèque au programme, vous pouvez la rechercher vous-même sur Google. Étant donné que certaines méthodes et structures de données de Python sont utilisées en C, le répertoire include sous le répertoire d'installation de Python doit être ajouté au répertoire d'inclusion du projet. D'accord, c'est tout ce dont vous avez besoin pour vous préparer, et vous pourrez ensuite commencer à mettre en œuvre un exemple de définition d'une zone mémoire.

Il existe de nombreuses façons d'exporter du C/C++ vers python Selon différents besoins, vous pouvez utiliser les différentes méthodes suivantes :

<.> 1. liaison ctypes. ctypes est inclus dans le module de bibliothèque standard universel de Python. Il peut charger des bibliothèques de liens dynamiques (dll, donc) au moment de l'exécution et est pris en charge sur CPython 2.x/3.x et PyPy. L'avantage de cette méthode est que vous n'avez pas besoin d'écrire la fonction d'exportation

spécifiquement en utilisant l'API python. Vous pouvez directement charger la table des symboles de la bibliothèque de liens dynamiques et l'appeler directement en python.

2. Liaison Python tierce. Les exemples incluent boost-python, qui est implémenté par l'automatisation d'outils à l'aide de l'API Python/C pour générer une série de fonctions wrapper C++. Particulièrement adapté à l'exportation de grandes bibliothèques ou de moteurs vers Python.


3. Écrivez manuellement la fonction de liaison python. Si vous êtes familier avec l'API Python C, cette méthode devrait être la plus flexible et vous pouvez l'utiliser après avoir lu la documentation de l'API. En théorie, l'efficacité devrait être la meilleure, mais pour un débutant en python comme moi, cela peut prendre beaucoup de temps.

Sur la base de mon expérience précédente dans l'exportation de fonctions C vers des scripts Lua, j'ai pensé que je devrais d'abord étudier l'API Python C, puis y travailler pendant une demi-journée avant de pouvoir le faire. Plus tard, j'ai découvert que les ctypes du module de bibliothèque standard Python sont déjà très puissants. Bien que les performances devraient être les pires parmi les trois méthodes, dans ce tunnel avec un maximum de 60 ips, la perte des appels de limite d'interface C/Python est ignorée. la première fois. Différent des deux autres méthodes de conception, ctypes utilise une méthode non invasive pour appeler l'interface. Il n'est pas nécessaire de modifier l'interface C d'origine ou d'écrire du code de liaison, et d'appeler directement la bibliothèque dynamique compilée. Le processus d'utilisation des ctypes est également très agréable.

Ce qui suit présente l'utilisation des ctypes :

1. Charger la bibliothèque de liens dynamiques DLL

Ici, vous devez faire attention pour distinguer si la fonction de bibliothèque de liens dynamiques utilise la convention d'appel cdecl ou stdcall, et utilise cdll ou windll pour charger la bibliothèque dynamique respectivement.


Par exemple :

# 加载udp库函数 
udp_server = cdll.LoadLibrary("./udp_server.so") 
init_udp_server = udp_server.init_udp_server 
destroy_udp_server = udp_server.destroy_udp_server 
update_udp_server = udp_server.update_udp_server 
SendMsg = udp_server.SendMsg 

SetConnectCallback = udp_server.SetConnectCallback 
SetDisconnectCallback = udp_server.SetDisconnectCallback 
SetTimeoutCallback = udp_server.SetTimeoutCallback 
SetRecvCallback = udp_server.SetRecvCallback

2 Type de données mappage

sauf ceux définis. par ctypes Les types de données de base (c_char, c_int, c_double, etc.) peuvent également être convertis en types pointeur à l'aide de la fonction pointeur. Pour que la bibliothèque réseau soit exportée, il est indispensable de définir la

fonction de rappel Dans la bibliothèque C++, la fonction de rappel est complétée par la définition d'un pointeur de fonction . . déclaration. Par exemple : , indiquant une fonction de rappel avec une valeur de retour void et des paramètres de types char* et int. recv_cb = CFUNCTYPE( None, c_char_p, c_int )


def init(self, port, ip="127.0.0.1"): 
  self._port = port 
  self._ip = ip 

  self._clients = {} 

  self.c_connect_cb = connect_cb(self.server_connect) 
  self.c_disconnect_cb = disconnect_cb(self.server_disconnect) 
  self.c_timeout_cb = timeout_cb(self.server_timeout) 
  self.c_recv_cb = recv_cb(self.server_recv) 

def create(self): 
  if self._port: 
   if init_udp_server(self._ip, self._port) == 0: 
    print "server listen %s:%d" % (self._ip, self._port) 
    SetConnectCallback( self.c_connect_cb ) 
    SetDisconnectCallback( self.c_disconnect_cb ) 
    SetTimeoutCallback( self.c_timeout_cb ) 
    SetRecvCallback( self.c_recv_cb ) 
    return True 
  print "[error] init_udp_server error", self._ip, self._port 
  return False
Lors de la liaison des paramètres de rappel, il convient de noter que la fonction de rappel liée doit être enregistrée en tant que variable membre (la méthode d'écriture ci-dessus) afin d'éviter python garbage collection. La fonction de rappel devient un pointeur sauvage. Ceci est considéré comme une petite fosse. Fondamentalement, une petite bibliothèque n'utilise que ces fonctions.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn