Mejore la velocidad de ejecución llamando a dll en Python

1. Introducción

En un proyecto reciente, era necesario grabar los comandos del teclado y el mouse y luego reproducir el proceso de grabación mediante inyección. En términos generales, algunos comandos de clic ordinarios se pueden completar a través de algunos paquetes de Python para completar operaciones de simulación de teclado y mouse, como a través del paquete pyautogui. Sin embargo, durante el proceso de movimiento del mouse, si la frecuencia es alta, como el muestreo de coordenadas de 50 píxeles como 1, encontrará que si la reproducción se realiza a través de Python, todo el proceso de reproducción, en comparación con el proceso de grabación original, es como reproducción lenta.
Todo el proceso se resume de la siguiente manera:
durante el proceso de registro, el muestreo se realiza cada vez T (registrando las coordenadas del punto). Dado que el muestreo en sí consume muy poco tiempo (menos de 0,1 ms), se puede ignorar. Por lo tanto, Si el proceso de grabación toma muestras de n puntos, el tiempo requerido es: nT
proceso de reproducción, es necesario moverse a cada punto p1, p2... de la muestra por turno, porque la función de Python realiza el movimiento a cada punto en el proceso de reproducción. moveTo, y la función moveTo se ejecuta una vez. El tiempo es t (aproximadamente 100 ms, que no se puede ignorar), por lo que el tiempo consumido por el proceso de reproducción es: nT + nt.
La relación de tiempo entre el proceso de reproducción y el proceso de grabación: (nT + nt)/nT = 1 + t/T, por lo que el proceso de reproducción es equivalente a 1 + t/T veces más lento que el proceso de grabación. Y cuanto mayor sea la frecuencia de muestreo, es decir, cuanto menor sea T, mayor será la proporción de reproducción lenta.
Proceso de grabación y muestreo.
Para acercar el proceso de reproducción al proceso de grabación, es decir, para reducir la proporción de reproducción lenta, es necesario escalar el tiempo de ejecución de moveTo. Dado que lleva mucho tiempo implementar moveTo a través de Python, moveTo se puede implementar a través de c/c++, lo que puede acortar en gran medida el tiempo requerido para moveTo.

2. Generar dll

Para llamar a dll en Python, primero debe generar el archivo dll de moveTo. El código fuente correspondiente es el siguiente:

// mouseMove.h
#ifdef MYDLL_EXPORTS
#define MATH_API __declspec(dllexport)
#else
#define MATH_API __declspec(dllimport)
#endif
#include <windows.h>
extern "C" {
    
    
	MATH_API void mouseClick(int x, int y);
	MATH_API void LeftDown(int x, int y);
	MATH_API void LeftUp(int x, int y);
	MATH_API void mouseMove(int x, int y);  // 对应moveTo函数
}
// mouseMove.cpp
void mouseClick(int x, int y) {
    
    
	INPUT input = {
    
     0 };
	input.type = INPUT_MOUSE;
	input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP;

	// 计算屏幕上的坐标位置
	input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
	input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);

	SendInput(1, &input, sizeof(INPUT));
}

void LeftDown(int x, int y) {
    
    
	INPUT input = {
    
     0 };
	input.type = INPUT_MOUSE;
	input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN;

	// 计算屏幕上的坐标位置
	input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
	input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);

	SendInput(1, &input, sizeof(INPUT));
}
void LeftUp(int x, int y) {
    
    
	INPUT input = {
    
     0 };
	input.type = INPUT_MOUSE;
	input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTUP;

	// 计算屏幕上的坐标位置
	input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
	input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);

	SendInput(1, &input, sizeof(INPUT));
}
void mouseMove(int x, int y) {
    
    
	INPUT input = {
    
     0 };
	input.type = INPUT_MOUSE;
	input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;

	// 计算屏幕上的坐标位置
	input.mi.dx = x * 65535 / GetSystemMetrics(SM_CXSCREEN);
	input.mi.dy = y * 65535 / GetSystemMetrics(SM_CYSCREEN);

	SendInput(1, &input, sizeof(INPUT));
}

Nota: No solo se implementa mouseMove (correspondiente a moveTo) en el archivo dll, sino que también se implementan mouseClick y otras operaciones de manera incidental.

3. Llame a dll a través de pyton

Para llamar a un archivo dll en Python, solo necesita importar primero el paquete ctypes, luego cargar el archivo dll a través del paquete ctypes y luego llamar a la función en el dll.

import ctypes
import pyautogui
# 加载dll文件
lib = ctypes.cdll.LoadLibrary("E:\\program\\cplusplus\\myDll\\x64\\Release\\myDll.dll")
# 调用dll中的函数
lib.mouseMove(100,200)

4. Comparación de la velocidad de ejecución entre la biblioteca Python y la biblioteca DLL

Todos sabemos que Python ciertamente no es tan rápido como c/c++, pero ¿cuál es la diferencia en la velocidad de ejecución? Si solo estuviéramos hablando de la función de mover el mouse mencionada en esta pregunta, ¡podría dar miedo decirlo! ! !
No hay imagen para contar. . . . ,

import time
import ctypes
import pyautogui
lib = ctypes.cdll.LoadLibrary("E:\\program\\cplusplus\\myDll\\x64\\Release\\myDll.dll")
t = time.time()
# dll执行1000次mouseMove
for i in range(0,1000):
    lib.mouseMove(i,2)
t1 = time.time()
print("mouseMove 1000 times by dll: ",t1 - t)
# 通过pyautogui执行100次moveTo
t = time.time()
for i in range(0,100):
    pyautogui.moveTo(i,300)
t1 = time.time()
print("moveTo 100 times by pyautogui:",t1 - t)

inserte la descripción de la imagen aquí
Como se puede ver en la figura, se necesitan 0,11 segundos para ejecutar 1000 veces de mouseMove a través de dll, y el tiempo promedio es de aproximadamente 0,1 ms. Se necesitan 10 segundos para
ejecutar 100 mouseTo a través de pyautogui, y el tiempo de consumo promedio de 100 ms
es de 1000 veces. ¿diferente? ? ?
No es de extrañar que el proceso de grabación se vuelva más lento cuando se convierte a reproducción en Python~
--------------------- Actualización ---------- ----- ------------------
Siempre ha sido difícil creer que las velocidades de las DLL de Python y C++ sean tan diferentes, pero en realidad no existe una diferencia tan grande. Básicamente, debería ser que pyautogui también llame a archivos DLL relacionados con la API de Windows. ¿Entonces, cuál es el problema?
Al estudiar el código fuente de pyautogui, se descubrió que la interfaz moveTo de pyautogui tiene un decorador y la mayor parte del tiempo se dedica al decorador.
inserte la descripción de la imagen aquí
Si se elimina el decorador, será equivalente a la velocidad de llamada de dll.

Artículos de referencia:
[1] Python llama a la biblioteca dll de C++
[2] C++ simula el movimiento del mouse y hace clic en el código de implementación
[3] [python] Python llama al programa C++

Supongo que te gusta

Origin blog.csdn.net/weixin_43354152/article/details/132395885
Recomendado
Clasificación