利用一个小游戏分析解释型语言与编译型语言差距

利用一个小游戏分析解释型语言与编译型语言差距,第1张

利用一个小游戏分析解释型语言与编译型语言差距

解释器与编译型语言的差距?

背景实现思路python实现C语言实现C版细节C语言版测试结果result

背景

从网上找到一个开源小游戏,经过删改简化,变成方块自己下落,点击最下一行红色方块即可消除,逐层下落,限时20s尽可能多但不准错.
所有文件可查看下面链接:
链接:资源
提取码:q6p8

实现思路

经过观察,我们发现能点击的那一层,中心坐标大概在y轴725的直线上
(点击开始后)

这时候,可以通过调查屏幕对应坐标处的像素点的颜色是否是红色的(如图的红色),是的话,就点击。
在这里依次判断四个位置,把x坐标带进去,y坐标始终是725
(测试屏幕坐标的方法,可以用pyautogui库,后台开一个cmd运行python,执行pyautogui.position(),打印当前鼠标坐标,利用这一方法,可将鼠标放在需要的位置,然后切屏,运行,得到坐标点)

python实现
from ctypes import *  # 获取屏幕上某个坐标的颜色

gdi32 = windll.gdi32
user32 = windll.user32

def getC():
	if gdi32.GetPixel(user32.GetDC(None), 600, 725) & 0x0000ff == 237:
		return 600
	if gdi32.GetPixel(user32.GetDC(None), 825, 725) & 0x0000ff == 237:
		return 825
	if gdi32.GetPixel(user32.GetDC(None), 1080, 725) & 0x0000ff == 237:
		return 1080
	if gdi32.GetPixel(user32.GetDC(None), 1325, 725) & 0x0000ff == 237:
		return 1325

# positions = [(600, 725), (825, 725), (1080, 725), (1325, 725)]

from time import sleep
from threading import Thread
import pyautogui as pg

can_continue = True

def count_time():
	sleep(20)
	can_continue = False

def main():
	# 切屏及开始时间
	sleep(1)
	Thread(target=count_time).start()
	while can_continue:
		# 计时器已启动
		pg.click(getC(), 725)

if __name__ == "__main__":
	main()

这是已经优化过的,程序解读主要是,开启一个子线程用来计时,防止程序一直 *** 作鼠标导致系统无法使用
然后getC()函数原本是获取RGB的,为了尽可能提高运行速度,改成直接返回x坐标,这样就免去了又一次取索引的内存 *** 作。
还有个小技巧,因为红色的RGB为定值,所以R为定值,那么只需要比较R和需要的R=237就行了,这是情况特殊可以如此优化,减少比较list这种相对较慢的 *** 作。

在python 3.9.6虚拟机中运行该脚本,花一秒切屏,让其自主 *** 作20秒自动结束。
平均得分大概在138-139(不同机器可能结果不同)

C语言实现
#include 
#include 
#include 

void click(int x, int y)
{
	SetCursorPos(x,y);
	mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);//鼠标左键按下 
	mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);//鼠标左键抬起
}

unsigned short getIndex()
{
	// 返回横坐标
	HDC hdc = GetDC(NULL);
	if (237 == GetRValue(GetPixel(hdc, 600, 725))) return 600;
	if (237 == GetRValue(GetPixel(hdc, 825, 725))) return 825;
	if (237 == GetRValue(GetPixel(hdc, 1080, 725))) return 1080;
	if (237 == GetRValue(GetPixel(hdc, 1325, 725))) return 1325;
	return 0;
}

int main()
{
	Sleep(2000);
	for (;;)
	{
		click(getIndex()/1.5, 725/1.5);
	}
	return 0;
}

通过c代码可以看出来,python版本就是利用ctypes调用了gdi32.dll等动态库的函数来通过系统API实现。那么C语言直接链接上,效果自然更好。
实现思路无变化,优化的思路也一样,只比较一个整形就够了,而且尽量数据大小小一点,比如这里short就够表示x坐标了使不上int这种32位的(虽然某种程度上,CPU的细节可能并不是这样思考的,也有可能int更快,但是样本太小了看不出来差别,就暂且这么强迫症地说着)
这个程序存在一个缺憾,就是它会无穷无尽地点击下去导致系统直接脱离控制,即使游戏结束。。。唯一的解决方案:alt+ctrl+delete然后注销,再登录,强制干掉这个进程。

C版细节
click(getIndex()/1.5, 725/1.5);

这一行,经过测试必须除以一个1.5,不然特别奇怪。
测试的过程很简单,我们用c语言分别调用
click(0, 10)
click(10, 0)
click(10, 10)
click(10, 20)
令(x0, y0)= 上面每组数据的click的参数
然后检测(x, y):用pyautogui,就是不移动鼠标,通过键盘 *** 作,调到控制台,然后输出坐标,得到(x, y)
多取几组数据,然后将每组对应的x0和x;y0和y,前者放x轴,后者y轴,画出图像,猜出来是一个正比例函数,比例系数k=1.5
(大家根据自己的设备及分辨率调整比例系数,这个没法统一,但是网上全是直接带入坐标…)

C语言版测试结果

各种手动优化(相对开始的代码,没贴出来)成这篇文章的版本后,加上-O3选项,预加载两次(也就是运行过这个程序,在系统不关闭的情况下,下次运行会更快,我也不知道为什么,但事实就是如此)
均分(20s)210

result

解释器的效率低下到不行,如果把游戏时间改到1000s之类的,差距会更明显。
分析得:c语言这个处理比python快52.17%
但是,值得考虑的是,这里频繁调用了Windows的api,所以并不能完全反应语言质量本身,虽然这个变量控制不变,但是实验中,绝不可能得到两种语言性能的绝对差距。
用数学知识易证,如果时间更长,两种语言的分数应该近似成正比例,但由于间隔越来越多,所以两者差值的导函数值越来越大。

综上所述:编译型语言效率远高于解释型语言,且效率差值随处理量成近似线性增长。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5711126.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存