Python语言多线程解析
小标 2018-12-10 来源 : 阅读 1335 评论 0

摘要:本文主要向大家介绍了Python语言多线程解析,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

本文主要向大家介绍了Python语言多线程解析,通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。

概述记得前些日子伞哥发过一个微博调侃过Python由于GIL锁的存在,所以现在死活想把自己和机器学习扯上关系。确实,由于这个全局解释锁的存在,任何时刻只有一个核在执行Python代码,这样就导致不能充分利用多核处理器的特性。但是,我们的程序也不总是在计算的,程序有IO密集型和CPU计算密集型。如果我们的程序需要等待用户输入,等待文件读写以及网络收发数据,那计算机就会把这些等待操作放到后台去处理,把CPU留出来用于计算。所以,虽然CPU密集型的程序用Python多线程确实无法提高效率,但是如果是IO密集型的程序,是可以使用多线程提高效率的。接下来,让我们通过例子一步一步了解多线程:利用threading模块使用多线程Python标准库自带了两个多线程模块,分别是threading和thread,其中,thread是低级模块,threading是对thread的封装,一般,我们直接使用threading即可。下面来看一个简单的多线程例子:import threadingdef say_hello():
    print("Hello world!")def main():
    for i in range(10):
        thread = threading.Thread(target=say_hello)
        thread.start()

main()在这个例子中,我们首先定义了要多线程执行的函数say_hello,然后我们在主函数里创建了10个线程,target取值是say_hi,告诉线程要执行的函数,然后我们调用start()方法吩咐线程去执行这些线程。这个程序最终会输出5个Hello world!,与["Hello world!" for i in range(10)]效果一致,那么为什么还要使用多线程呢,我们通过下面这个例子理解下多线程的意义:import threadingimport timedef say_hello():
    time.sleep(1)
    print("Hello world!")def main():
    for i in range(10):
        thread = threading.Thread(target=say_hello)
        thread.start()

main()在这个例子里,我们加了time.sleep(1)来模拟等待事件。现在如果用普通的循环来迭代,代码执行完需要至少5秒,而多线程运行只需要1秒多,减少了程序整体运行的时间。给线程传参和线程常用方法在上面的代码中,我们并没有给say_hello传参数,在多线程里传参很简单,只需要这样做就好了:import threadingdef say_hello(count, name):
    print("Hello world!", name)
    count -= 1def main():
    name_list = ['Bob', 'Jack', 'Jone', 'Mike', 'David']    for i in range(5):
        thread = threading.Thread(target=say_hello, args=(10, name_list[i]))
        thread.start()

main()在threading.Thread类中,常用的方法有:isAlive: 检查线程是否在运行中getName: 获取线程名称setName: 设置线程名称join:阻塞线程调用,直到线程中止setDaemon:设置线程为守护线程isDaemon: 判断线程是否是守护线程通过继承创建线程除了直接实例化threading.Thread对象,我们还可以通过继承threading.Thread来编写多线程的类。然后把多线程调用的函数携程一个run方法。方法如下:import threadingclass MyThread(threading.Thread):
      def __init__(self, count, name):          super(MyThread, self).__init__()          self.count = count          self.name = name     
      def run(self):          while self.count > 10:
                print("hello", self.name) 
                self.count -= 1线程与互斥锁多个线程之间 内存是共享的,所以线程比进程轻量。多个线程是可以同时访问内存中的数据的,如果多个线程同时修改一个对象,那这份数据可能会被破坏,Python的threading类中提供了Lock方法,它会返回一个锁对象,一般通过lock.acquire()来获取锁,通过lock.release()来释放锁,对于那种只允许一个线程操作 的数据,一般把对其的操作放在lock.acquire()和lock.release()中间。无论在什么情况下,我们都要保证代码要释放锁,所以其他语言中一般把加锁和释放锁放在try/finally语句中。在Python中,其实我们可以用上下文管理器来简化代码,关于上下文管理器的介绍可以参考我前面的文章:上下文管理器,这里我们可以这样使用锁:with lock:    #lock processing下面来看一个使用互斥锁的例子,在这个例子中,我们使用了全局变量,然后创建10个线程,每个线程做同样的事情,由于num是全局变量,而且每个线程都需要使用这个变量,因此存在着数据争用的问题,所以,我们就需要使用互斥锁保护这个全局变量:所有修改这个变量的线程在修改前都需要加锁,在increment函数中,我们通过with语句进行加锁。如下所示:import threading

lock = threading.Lock()
num = 0def increment(count):
    global num    while count > 0:        with lock:
            num += 1
        count -= 1def main():
    threads = []    for i in range(10):
        thread = threading.Thread(target=increment,args=(100,))
        thread.start()
        threads.append(thread)    for thread in threads:
        thread.join()

    print("except value is 1000, real value is{}".format(num))
    
main()有兴趣的读者可以试试把锁去掉是什么结果,实际上,我们永远得不到正确的结果。对于这段代码,我们可以这样理解:    threads = []    for i in range(10):
        thread = thread.Threading(target=increment, args=(100,))
        thread.start()
        threads.append(thread) 
    for thread in threads:
        thread.join()第一个for循环,意思是吩咐十个线程去做target里面的事,执行完第一个for循环后就吩咐完了,但仅仅是只是吩咐完了,target里面的任务没有执行完,因为不知道是否执行完,所以还需要创建一个列表把他们都保存起来。对于第二个for循环,如果在第一个循环里 他们的target已经执行完了,那后面直接就join,不用等待,遇到有的线程没有执行完的,join 就阻塞调用,直到这些线程执行完。线程安全队列queue队列是线程间最常用的交换数据的形式,queue模块实现了线程安全的队列,有三种类型的队列:queue Queue:FIFO(先进先出) 的队列。最常用的队列!queue LifoQueue: LIFO(后进先出)的队列,最后加入队列的元素最先取出queue PriorityQueue: 优先级队列,队列中的元素根据优先级排序。下面是Queue类常用的方法:empty: 判断队列是否为空full: 判断队列是否已满put: 向队列中添加元素get: 从队列中取出元素put_nowait: 非阻塞 向队列中添加元素get_nowait: 非阻塞 从队列中取出元素join:阻塞等待,直到所有任务完成来看一个官方给的多线程模型:def worker():
    while True:
    item = q.get()
    do_work()
    q.task_done()

q = Queue()for i in range(thread_number):
    t = Thread(target=worker)
    t.daemon = True
    t.start()for item in source():
    q.put(item)  

q.join()之后会有一个线程池的例子运用Queue队列。

本文由职坐标整理并发布,希望对同学们学习Python有所帮助,更多内容请关注职坐标编程语言Python频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved