优化python程序执行速度

这篇具有很好参考价值的文章主要介绍了优化python程序执行速度。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、问题背景

     最近使用python编写的一个蓝牙应用程序,在使用过程中发现传输大量数据时会产生丢包,导致无法接收到完整的数据包。蓝牙接收程序的代码如下。

#蓝牙数据接收处理线程
    def bt_recv_thread(self):
        recv_time = time.time()
        while(self.thread_run):
            try:
                recv_data = self.client_socket.recv(1024)
            except Exception as e:
                self.log.logprint(e)
                self.client_socket.close()
                self.client_socket = None
                self.thread_run = False
                break
            #print("recv data:", recv_data.hex())

            #接收2秒超时,清除原来的接收数据
            if(time.time() - recv_time) > 2 and self.recv_index != 0:
                self.log.logprint("recv data timeout, index:%d, msg_len:%d"%(self.recv_index, self.msg_len))  
                self.recv_index = 0
                self.msg_len = 0  
            recv_time = time.time()

            for d in recv_data:
                if d.to_bytes(1, "little") == T95_BT_HEAD_1 and self.recv_index == 0:
                    self.msg_len = 0
                    self.recv_index = 1
                    self.recv_msg = d.to_bytes(1, "little")

                elif d.to_bytes(1, "little") == T95_BT_HEAD_2 and self.recv_index == 1:
                    self.recv_index = 2
                    self.recv_msg += d.to_bytes(1, "little")

                elif d.to_bytes(1, "little") == T95_BT_HEAD_3 and self.recv_index == 2:
                    self.recv_index = 3
                    self.recv_msg += d.to_bytes(1, "little")    

                elif d.to_bytes(1, "little") == T95_BT_HEAD_4 and self.recv_index == 3:
                    self.recv_index = 4
                    self.recv_msg += d.to_bytes(1, "little") 

                #8-15是报文总长度, 占用8个字节
                elif self.recv_index == 15:
                    self.recv_msg += d.to_bytes(1, "little")
                    self.recv_index += 1 
                    self.msg_len = int.from_bytes(self.recv_msg[8:16], byteorder="big")     

                #接收到帧尾,并且长度等于帧头
                elif self.recv_index == (self.msg_len - 1) and d.to_bytes(1, "little") == T95_BT_TAIL:
                    self.recv_msg += d.to_bytes(1, "little")
                    self.recv_index = 0

                    #处理消费一个整帧数据,计算数据CRC
                    crc = int.from_bytes(self.recv_msg[-5:-1], byteorder="big")

                    if crc != self.CRC32_cacl(self.recv_msg[:-5]):
                        self.log.logprint("CRC 32 error!") 
                        continue

                    #判断数据帧类型
                    msg_type = int.from_bytes(self.recv_msg[16:20], byteorder="big")
                    seq = int.from_bytes(self.recv_msg[5:7], byteorder="big")
                    if msg_type == T95_BT_MSG_TYPE_CON_REQ:
                        #局放主动发送的心跳数据,回复应答
                        self.send_t95(T95_BT_MSG_TYPE_CON_ACK, T95_BT_ACK_FLAG, seq, b"", b"")

                    elif msg_type == T95_BT_MSG_TYPE_DATA_UPLOAD:
                        #局放主动发送的检测数据,回复应答
                        self.send_t95(T95_BT_MSG_TYPE_DATA_ACK, T95_BT_ACK_FLAG, seq, b"", b"") 
                        msg_len  = int.from_bytes(self.recv_msg[39:47], "big")
                        msg_data = self.recv_msg[47:47+msg_len]

                        file_len = int.from_bytes(self.recv_msg[47+msg_len:55+msg_len], "big")
                        file_data = self.recv_msg[msg_len+55: msg_len+55+file_len]
                        
                        #通过回调函数来处理业务数据与文件
                        if self.check_file_notify_call != None:
                            self.check_file_notify_call(msg_data, file_data)       
                    else:
                        #发送给其他线程处理   
                        self.rcv_sem.release()

                else:
                    self.recv_msg += d.to_bytes(1, "little")
                    self.recv_index += 1

     首先怀疑的是代码逻辑有问题,经过阅读代码与测试,发现代码逻辑正确。其次怀疑设备的蓝牙驱动程序有问题,使用了手机与设备进行蓝牙文件传输也正常。把这份代码移植到笔记本电脑上面运行,测试大数量时依然为丢包。

     最后怀疑代码执行慢了,导致未能及时从蓝牙设备中读取到接收的数据。

2、解决办法

      分析代码,代码中变量self.recv_msg使用bytes字节串来存储接收到的数据,程序首先从蓝牙设备中读取数据存储在recv_data字节串中,之后遍历整个字节串,把数据放到self.recv_msg中去。

      理论分析:由于bytes是不可变字节串,self.recv_msg += d.to_bytes(1, "little")这名代码相当把字节串与一个新的字节串d.to_bytes(1, "little")连接形成一个新的字节串,这此操作中一共要处理3个字节串,都需要在内存中创建这三个字节串,随着接收数据量的变大,会耗费更多的时间处理。

  理论验证:编写python程序测试list, bytes, bytearray三种数据类型在大数据量时的处理速度,测试的数据量为100万个数据。

#! /usr/bin/python3.8
# -*- coding: utf-8 -*-

import time

num = 1000000
a = []
b = bytearray()
bb = b"\x02" * num
d = b""

start_time = time.time()
for i in range(num):
    a.append(i&0xff)

stop_time = time.time()
print("list start time:%d, end time:%ds, pass:%fs"%(start_time, stop_time, stop_time-start_time))   

start_time = time.time()
for i in bb:
    b.extend((i&0xff).to_bytes(1, "little"))

stop_time = time.time()    
print("bytearray start time:%d, end time:%ds, pass:%fs"%(start_time, stop_time, stop_time-start_time))


start_time = time.time()
for i in bb:
    d +=(i&0xff).to_bytes(1, "little")

stop_time = time.time()    
print("byte start time:%d, end time:%ds, pass:%fs"%(start_time, stop_time, stop_time-start_time))


c = bytes(b)
print("bytearray",b[0:5])   
print("int",int.from_bytes(b[0:5], byteorder="big")) 
for i in c:
    d = i
print("bytes", c[0:23])

    代码的运行结果如下:

优化python程序执行速度,pyqt5编程,编程经验,python,网络,开发语言,蓝牙

     从以上结果可以看出,处理100万个数据时,list速度最快,用时0.126秒,bytearray,居中,用时0.270秒, bytes最慢,用于98秒。根据程序的处理数据的需要,代码改动少的情况下使用bytearray来处理,可以提高处理速度。改进后的代码如下:

#蓝牙数据接收处理线程
    #由于bytes是不可变序列,因此在做增加操作时,会新生成一个bytes导致程序处理速度很慢,因此使用可变序列bytearray
    def bt_recv_thread(self):
        recv_time = 0
        while(self.thread_run):
            try:
                recv_data = self.client_socket.recv(1024)
            except Exception as e:
                self.log.logprint(e)
                self.thread_run = False
                break
            #print("recv data:", recv_data.hex())

            #接收2秒超时,清除原来的接收数据
            if self.recv_index != 0 and (time.time() - recv_time) > 2:
                self.log.logprint("recv data timeout, index:%d, msg_len:%d"%(self.recv_index, self.msg_len))  
                self.recv_index = 0
                self.msg_len = 0  
            recv_time = time.time()

            for d in recv_data:
                d_bytes = d.to_bytes(1, "little")
                if d_bytes == T95_BT_HEAD_1 and self.recv_index == 0:
                    self.msg_len = 0
                    self.recv_index = 1
                    self.recv_msg = bytearray(d_bytes)

                elif d_bytes == T95_BT_HEAD_2 and self.recv_index == 1:
                    self.recv_index = 2
                    self.recv_msg.extend(d_bytes)

                elif d_bytes == T95_BT_HEAD_3 and self.recv_index == 2:
                    self.recv_index = 3
                    self.recv_msg.extend(d_bytes)    

                elif d_bytes == T95_BT_HEAD_4 and self.recv_index == 3:
                    self.recv_index = 4
                    self.recv_msg.extend(d_bytes) 

                #8-15是报文总长度, 占用8个字节
                elif self.recv_index == 15:
                    self.recv_msg.extend(d_bytes)
                    self.recv_index += 1 
                    self.msg_len = int.from_bytes(self.recv_msg[8:16], byteorder="big")     

                #接收到帧尾,并且长度等于帧头
                elif self.recv_index == (self.msg_len - 1) and d_bytes == T95_BT_TAIL:
                    self.recv_msg.extend(d_bytes)
                    self.recv_index = 0

                    #处理消费一个整帧数据,计算数据CRC
                    crc = int.from_bytes(self.recv_msg[-5:-1], byteorder="big")

                    if crc != self.CRC32_cacl(self.recv_msg[:-5]):
                        self.log.logprint("CRC 32 error!") 
                        continue
                    self.log.logprint("receive the data len:%d"%(self.msg_len))
                    #判断数据帧类型
                    msg_type = int.from_bytes(self.recv_msg[16:20], byteorder="big")
                    seq = int.from_bytes(self.recv_msg[5:7], byteorder="big")
                    if msg_type == T95_BT_MSG_TYPE_CON_REQ:
                        #局放主动发送的心跳数据,回复应答
                        self.send_t95(T95_BT_MSG_TYPE_CON_ACK, T95_BT_ACK_FLAG, seq, b"", b"")

                    elif msg_type == T95_BT_MSG_TYPE_DATA_UPLOAD:
                        #局放主动发送的检测数据,回复应答
                        self.send_t95(T95_BT_MSG_TYPE_DATA_ACK, T95_BT_ACK_FLAG, seq, b"", b"") 
                        msg_len  = int.from_bytes(self.recv_msg[39:47], "big")
                        msg_data = self.recv_msg[47:47+msg_len]

                        file_len = int.from_bytes(self.recv_msg[47+msg_len:55+msg_len], "big")
                        file_data = self.recv_msg[msg_len+55: msg_len+55+file_len]
                        
                        #通过回调函数来处理业务数据与文件
                        if self.check_file_notify_call != None:
                            self.check_file_notify_call(msg_data, file_data)       
                    else:
                        #发送给其他线程处理   
                        self.rcv_sem.release()

                else:
                    self.recv_msg.extend(d_bytes)
                    self.recv_index += 1
        self.client_socket.close()
        self.client_socket = None

     经过以上的代码优化和测试后,蓝牙传输大量数据时不再丢包,完美解决问题。文章来源地址https://www.toymoban.com/news/detail-734759.html

到了这里,关于优化python程序执行速度的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PyQt5多线程的执行和停止

    参考资料:哔哩哔哩 pyqt5 thread多线程示例 以下代码来自该视频,我自己手动实现了一下,当作一个模板来学习,欢迎大家一起学习。 运行示例 三个进程同时执行,并且可以单独控制暂停和继续执行。 以下给出运行代码: 完整程序参考:PyQt5 多线程执行和停止示例

    2024年02月16日
    浏览(38)
  • pyqt5 如何终止正在执行的线程?

    在 PyQt5 中终止正在执行的线程,可以通过一些协调的方法来实现。一般情况下,直接强行终止线程是不安全的,可能会导致资源泄漏或者程序异常。相反,我们可以使用一种协作的方式,通知线程在合适的时候自行退出。 以下是一种常见的方法,使用标志位来通知线程停止

    2024年02月14日
    浏览(40)
  • 数据库系统课设——基于python+pyqt5+mysql的酒店管理系统(可直接运行)--GUI编程(2)

     几个月之前写的一个项目,通过这个项目,你能学到关于数据库的触发器知识,python的基本语法,python一些第三方库的使用,包括python如何将前后端连接起来(界面和数据),还有界面的设计等等。希望大家能从项目中学到东西。 宾馆管理系统通过提供顾客和员工信息之间

    2024年02月03日
    浏览(57)
  • 【PyQt5】构建强大的Python图形用户界面应用程序 -- 入门指南

      作者主页: 爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主 爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域. https://blog.csdn.net/Code_and516?type=blog 个人简介:打工人。 持续分

    2024年02月15日
    浏览(54)
  • pyqt5优化美化界面代码

    自用的pyqt5界面优化美化代码,方便自己写界面时复制,也顺便造福广大网友吧! 首先安装基础工具: Pycharm配置QtDesigner(PyUIC、PyRcc ) 并懂得如何规范化创建qt界面: QtDesigner规范创建应用界面 文章将持续更新....... 鼠标不置于其上效果: 鼠标置于其上但不点击效果: 点击效

    2024年02月03日
    浏览(47)
  • PyQt5 GUI编程

    PyQt5是一个用于创建图形用户界面(GUI)应用程序的跨平台工具集,它将Qt库(广泛用于C++编程语言中创建丰富的GUI应用程序)的功能包装给Python使用者。PyQt5是由Riverbank Computing开发的,并且可以在所有主流操作系统上运行,包含Windows、macOS和Linux。 PyQt5包括了超过620个类和

    2024年03月19日
    浏览(47)
  • PyQt5 执行耗时操作导致界面卡死或未响应的解决办法

    当用PyQt5开发一个GUI界面 ,需要执行业务逻辑时,后台逻辑执行时间长,界面就容易出现卡死、未响应等问题。 在PyQt中,GUI界面本身就是一个处理事件循环的主线程,当进行耗时操作时,主线程GUI需要等待操作完成后才会响应,在等待这段时间,整个GUI就处于卡死的状态。

    2024年02月09日
    浏览(40)
  • PyQt5 GUI编程界面与函数相连

    在使用PyQt5的时候会出现一些需求 无法用代码一步步实现 ,而用GUI画完窗口之后,又要根据pyUIC5 自动生成的界面的参数 进行编程,这样增加了理解变量所需的时间。我查到了一个解决办法,就是 将界面设计与函数实现分开分别写 ,并用一个巧妙的方法将这俩在代码层面进

    2024年02月05日
    浏览(45)
  • PyQt5 GUI编程(QMainWindow与QWidget模块结合使用)

    QWidget是所有用户界面对象的基类,而QMainWindow 用于创建主应用程序窗口的类。它是 QWidget 的一个子类,提供了创建具有菜单栏、工具栏、状态栏等的主窗口所需的功能。上篇主要介绍了基本使用,创建窗口时都是继承单个模块,本章主要介绍下两个模块的结合使用。 1.我们先

    2024年04月08日
    浏览(77)
  • 【Python进阶-PyQt5】00搭建PyQt5环境

    我们编写的程序,有时用到的Python库是不一样的,比如说开发桌面应用程序我们主要用到PyQt5相关的Python库、开发Web应用程序我们主要用到Django相关的Python库等等。假设我们在开发桌面应用程序的时候除了PyQt5相关的Python库外,还附加了其他的Python库,比如有关Django的Python库。

    2024年02月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包