zoukankan      html  css  js  c++  java
  • 【Python】多线程个人使用理解之_thread

    Python 并发编程个人理解

    在工作中遇到了一些Python编程中的问题,借此学习了Python的并发编程。网上说的都很好,我就不重复说了。我说说自己在实际运用中的理解。

    我的需求是要在一个脚本里面实现一个对游戏按钮非常快的连续点击,但是使用的框架却是非常慢的,单线程远远达不到要求。

    这个时候我考虑到了使用Python的多线程。通过了解,我知道了Python有俩个多线程API,一个是比较简单的_thread,一个是提供了多种功能thread的类,由于使用thread需要继承Thread类,我想我就一个click函数太麻烦了,就使用的_thread方法。

    _thread --- 底层多线程 API
    https://docs.python.org/zh-cn/3/library/_thread.html

    我们来看一下这段代码:

    def cli():
        button.click()
    def func():
        for i in range(100):
            while button.exist():
                _thread.start_new_thread(cli,())
        button2.click()            

    这段代码是有问题的,我们来一一捋以下。

    首先,多线程线程的代码执行逻辑中并不是顺序的,并不是你在中间开了多线程以后,你的主线程逻辑会乖乖等这一段代码执行完然后进入下一段,线程的执行顺序是由操作系统决定的,涉及资源的调度。如果你的业务逻辑是点击了button才会出现button2,点击button2以后才会出现button3,那么有可能出现尝试点击button2,然后button的线程才开始陆续生成,很明显,这就抛异常了。
    面对这种解决方法,就是在这里让主线程中断一下,让多线程跑起来。最常见的有两种解决方法,一种是在中间加上sleep,另一种是使用python语法糖,使用[]把线程的生成限制在list的生成中。

    #第一种
    def func():
        for i in range(100):
            while button.exist():
                _thread.start_new_thread(cli,())
            while button.exist():
                time.sleep(10)
            button2.click()
    #第二种
    def a_thread():
        while button.exist():
            _thread.start_new_thread(click,())
    def func():
        [a_thread() for i in range(100)]
        button2.click()    

    当然,还有问题。你是干一件事一次开一个线程,还是开多个线程每次干一件事呢?这就好比你去打仗,你要在限定时间内杀死多个敌人,你是看一遍敌人在不在,然后派一个士兵去打仗,还是同时派多个士兵去,让士兵们去判断敌人在不在自己去打仗好呢?显然是后者效率更高的。

    def cli():
        while button.exist():
            button.click()
    def func():
        for i in range(100):
            _thread.start_new_thread(cli,())
        while button.exist():
            time.sleep(10)
        button2.click()

    按理说,到了这一步,应该是没问题了,但是实际上忽略了一个问题。我们使用_thread方法创建的线程都在抢占button这个资源,如果一个线程没有抢到,该线程会异常退出。这就导致了一开始开了很多个线程,但是持续有线程死掉,这样到了后期点击的速度就会慢下来。
    为了解决这个问题,我们需要对共享的资源加锁,这一篇文章讲的很明白,我就不再阐述了。

    Python并发编程之谈谈线程中的“锁机制”(三)
    https://juejin.im/post/5b17f4305188257d6b5cff6f

    修改后的代码如下。

    def cli(loc):
        while button.exist():
            with loc:
            button.click()
    def func():
        loc = _thread.allocate_lock()
        for i in range(100):
            _thread.start_new_thread(cli,(loc,))
        while button.exist():
            time.sleep(10)
        button2.click()
    

    如果你读过Python Cookbook你会发现,它更多的是介绍threading的使用。threading提供了更高级的线程管理用法,比如更多的同步原语等。我也使用了threading做了实验,但实际上thread模块更接近线程的底层结构,并发速度更快,更能解决我的实际需求。

    threading具体可以参考Python Cookbook:
    Python Cookboob 第十二章:并发编程
    https://python3-cookbook.readthedocs.io/zh_CN/latest/chapters/p12_concurrency.html

  • 相关阅读:
    运行JBoss 5.1.0 GA时出现Error installing to Instantiated:name=AttachmentStore state=Described错误的解决办法
    java中log4j的使用体验
    C#:DataTable映射成Model
    使用MyBatis搭建一个访问mysql数据库的简单示例
    netty的拆包和粘包
    netty的HelloWorld演示
    ByteBuffer详解
    汉字拼音缩写输出工具类
    mysql错误汇集
    mysql的定时任务
  • 原文地址:https://www.cnblogs.com/guangluwutu/p/13344012.html
Copyright © 2011-2022 走看看