文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

浅析Python中线程以及线程阻塞

2023-05-17 08:42

关注

本文所依赖的环境为:

进程和线程的概念

进程概念

我们想运行一个程序,首先会将该程序从存储介质上通过IO总线加载进内存中,而后再通过cpu进行调度。这个时候,我么么将这个正在运行的程序称之为进程,它有内存地址、内存空间、数据栈等等信息,进程之间通信一般称之为IPC,常见的方法有 管道、消息队列、套接字等。

线程概念

而线程则不同,线程是在进程中运行的,一个进程至少有一个线程。在单个cpu中,同一时刻一个进程只有一个线程在工作,其他则被挂起,也称之为睡眠。由于线程属于进程,所以会共享进程的内存信息。线程之间通信不仅可以使用共享内存来通信,依然可以使用 如 管道、消息队列、套接字等。

线程优缺点

多线程是一种并发方式,优点为可以同时执行多个任务,用于提升时间和效率。

比如,我们想写一个python服务器下载电影,一次只能下载一部,若我们使用多线程后,可以一次"同时"下载n部,从而提升了效率。

但是有些事多线程不能做的,并发冲突是其中一种。比如掘金点赞功能,如果没有对点赞这个变量进行并发控制,可能会出现数据不一致的情况。

在python中如何使用线程

在使用python写多线程之前,先来看一个小案例,假设我们使用python写了一个下载电影的程序。

import time

def downloadMovie(i):
    print("%s 开始下载编号为%s电影中。。。" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))
    time.sleep(5)
    print("%s 编号为%s电影下载完毕" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))

def main():
    for i in range(5):
        downloadMovie(i)

if __name__ == '__main__':
    main()

我们假设模拟下载电影的一个程序,下载过程使用time.sleep代替。在没有使用多线程的时候,它的执行过程如下:

可以看到,它是顺序执行的,需要等上一部下载完毕,才能开始下载下一部。

如果使用线程来做该需求呢? 我们可以这样来写:

import time
import threading

def downloadMovie(i):
    print("%s 开始下载编号为%s电影中。。。" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))
    time.sleep(5)
    print("%s 编号为%s电影下载完毕" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), str(i)))

def main():
    for i in range(5):
        t = threading.Thread(target=downloadMovie,args=(i,))
        t.start()

if __name__ == '__main__':
    main()

上述代码,在原始代码基础上,我们引入了threading库,在循环中使用Thread来做线程的实例化对象,我们需要传入targetargstarget需要传入函数名称,args需要传入参数,注意这里参数需要传入可迭代的对象,所以当只有一个参数的时候,也需要在后面加一个,。最后使用start方法让其开始执行。

运行后的效果如下:

可以发现,我们程序几乎同步的打印下载开始,也几乎同时打印下载完毕。

总结起来发现,我们线程启动一个线程,是不是非常简单呢?只需要引入threading模块,定义Thread来做对象,最后使用start()运行即可。

线程阻塞也很重要

线程直接跑就完了呗,为什么还需要阻塞呢?我们这里做一个简单的需求:上面的代码改改,我们下载完视频后,要压缩一下,由于只讨论线程,所以就只用print代替操作,我们可以这样操作:

在上面的基础上,我们增加了2个步骤,1: 是将下载好的文件放入列表fileList中,2. 最后开始遍历fileList文件,进行压缩,最后打印一个压缩完毕,看起来没什么问题吧?

那我们来运行一下一下呢?

额。。。这个很显然不符合我们的预期,我们还没下载文件完毕,怎么就开始压缩了呢,而且压缩完毕了,再输出的文件下载完毕,这是为什么呢?

这是因为线程在启动后,如果我们不去设置阻塞,他就会一直执行下去,就拿我们刚才的案例来看,我们可以将其理解为:

看上图,我们启动线程后,它就放在后台了,我们就立马执行遍历fileList步骤,但是这个时候恰恰fileList是空的,所以我们压缩了空文件,压缩完毕后,文件才下载完毕。

这个时候我们就需要等线程执行完毕之后,再执行下面的语句了,否则执行完了没意义,所以这个时候就需要引入线程阻塞了,我们需要将下载的线程全部执行完毕后,再开始压缩文件,只需要线程增加一个join方法即可,代码修改如下:

在原先的基础上,我们需要先定义一个线程池,用于放已经执行了的线程,而后再遍历该线程池,每一个都设置阻塞,这样就会等所有线程都执行完毕了,再进行后面的操作,由于我们后面是压缩需要用到前面的结果,所以阻塞是必不可少的,程序执行结果为:

这个流程图可以理解为这样的:

现在你知道阻塞有什么用了吧。

总结

今天介绍了一下python的多线程,这里只是简单的使用threading库,在python中,多线程的库不仅于此,还有threadQueue等。最后举了一个很简单的例子来说明线程阻塞的重要性。

以上就是浅析Python中线程以及线程阻塞的详细内容,更多关于Python线程的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯