python|初始线程以及线程阻塞

简介: python|初始线程以及线程阻塞

本文所依赖的环境为:

image.png


进程和线程的概念


进程概念

我们想运行一个程序,首先会将该程序从存储介质上通过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代替。在没有使用多线程的时候,它的执行过程如下:

image.png


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

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

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方法让其开始执行。


运行后的效果如下:

image.png

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

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



线程阻塞也很重要


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

image.png


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

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

image.png


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


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

image.png

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


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

image.png


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

image.png


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

image.png


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



总结


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



相关文章
|
6天前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
20 3
|
6天前
|
安全 数据安全/隐私保护 数据中心
Python并发编程大挑战:线程安全VS进程隔离,你的选择影响深远!
【7月更文挑战第9天】Python并发:线程共享内存,高效但需处理线程安全(GIL限制并发),适合IO密集型;进程独立内存,安全但通信复杂,适合CPU密集型。使用`threading.Lock`保证线程安全,`multiprocessing.Queue`实现进程间通信。选择取决于任务性质和性能需求。
19 1
|
6天前
|
Python
解锁Python并发新世界:线程与进程的并行艺术,让你的应用性能翻倍!
【7月更文挑战第9天】并发编程**是同时执行多个任务的技术,提升程序效率。Python的**threading**模块支持多线程,适合IO密集型任务,但受GIL限制。**multiprocessing**模块允许多进程并行,绕过GIL,适用于CPU密集型任务。例如,计算平方和,多线程版本使用`threading`分割工作并同步结果;多进程版本利用`multiprocessing.Pool`分块计算再合并。正确选择能优化应用性能。
|
7天前
|
安全 Java 调度
「Python入门」Python多线程
1. **线程与进程区别**:线程共享内存,进程独立;线程启动快,多线程效率高于多进程。 2. **多线程使用**:直接使用Thread类,通过`target`指定函数,`args`传递参数;或继承Thread,重写`run`方法。 3. **守护线程**:设置`setDaemon(True)`,主线程结束时,守护线程一同结束。 4. **join线程同步**:主线程等待子线程完成,如`t.join()`。 5. **线程锁**(Mutex):防止数据竞争,确保同一时间只有一个线程访问共享资源。 6. **RLock(递归锁)**:允许多次锁定,用于需要多次加锁的递归操作。
16 1
「Python入门」Python多线程
|
1天前
|
消息中间件 安全 数据处理
Python中的并发编程:理解多线程与多进程的区别与应用
在Python编程中,理解并发编程是提高程序性能和响应速度的关键。本文将深入探讨多线程和多进程的区别、适用场景及实际应用,帮助开发者更好地利用Python进行并发编程。
|
2天前
|
缓存 并行计算 监控
了解 Python 线程
【7月更文挑战第8天】在Python多线程编程中,`threading`模块允许我们获取当前线程名字,通过`current_thread().name`获取。线程名字有助于调试、日志和资源管理。示例代码展示了如何创建线程并打印其名字。在实际应用中,线程命名应清晰、唯一且避免特殊字符,以提高代码可读性和维护性。多线程编程需注意线程安全、死锁、性能优化等问题。通过合理设计和测试,可以利用多线程提高程序并发性和效率。
6 1
|
3天前
|
Python
告别阻塞,拥抱未来!Python 异步编程 asyncio 库实战指南!
【7月更文挑战第12天】Python的`asyncio`库是异步编程的关键,它允许程序在等待IO操作时执行其他任务,提升效率。异步函数用`async def`定义,`await`用于挂起执行。
15 1
|
5天前
|
数据库 数据安全/隐私保护 C++
Python并发编程实战:线程(threading)VS进程(multiprocessing),谁才是并发之王?
【7月更文挑战第10天】Python并发对比:线程轻量级,适合I/O密集型任务,但受GIL限制;进程绕过GIL,擅CPU密集型,但通信成本高。选择取决于应用场景,线程利于数据共享,进程利于多核利用。并发无“王者”,灵活运用方为上策。
|
6天前
|
安全 API 调度
深度剖析:Python并发编程中的线程与进程,那些你不可不知的使用技巧与限制!
【7月更文挑战第9天】Python并发:线程适合IO密集型任务,利用GIL下的多线程同步,如示例中使用锁。进程适用于CPU密集型,通过multiprocessing模块实现多进程,利用进程间通信如队列。线程受限于GIL,进程间通信成本高。选择取决于任务需求和性能目标。
12 2
|
1天前
|
网络协议 安全 Python
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
我们将使用Python的内置库`http.server`来创建一个简单的Web服务器。虽然这个示例相对简单,但我们可以围绕它展开许多讨论,包括HTTP协议、网络编程、异常处理、多线程等。
5 0

相关实验场景

更多