python常用模块(Thread,Lock,Queue,ThreadPool)

引入一下线程和进程的理解性概念:

进程: 打开一个程序至少会有一个进程  它是cpu调度的最小的单位。
线程: 程序执行的最小单位,一个进程里面至少有一个线程,cpu会控制进程里面的线程。

打个比方:(1)打开一个qq就是一个进程的话,那么你可以同时和好多人聊天,和一个人聊天这就是一个线程。
        (2)再打个比方,一条直行的高速公路,分好几个车道,这整个告诉公路就相当于一个进程,
            那些车道就相当于一个个线程,如果有一条车道上的车拐弯,别的车道的车就要等待,不然就撞车了。
注意:
(1)一个cpu同一时间只能处理一件事,如果同时有多个任务,那么就轮换着执行,但是每个任务执行的时间非常短暂,无法感受到。
(2)使用线程的时候,不管它的顺序,因为cpu是随机调度的。
(3)一个程序的执行,就会有一个主线程

阶段一:线程的实现

1.线程模块

Python通过两个标准库thread 和threading提供对线程的支持 , threading对thread进行了封装。threading模块中提供了Thread , Lock , RLock , Condition等组件。

							因此在实际的使用中我们一般都是使用threading

2.Thread类

在这里插入图片描述在这里插入图片描述

3.创建线程

在python中创建线程有两种方式,实例Thread类和继承重写Thread类实例Thread类

实例Thread类:
在这里插入图片描述

4.创建线程

继承Thread类
在这里插入图片描述

5.Join & setDaemon

(1)

在说这两个方法之前 , 需要知道主线程与子线程的概念

主线程 : 当一个程序启动时 , 就有一个线程开始运行 , 该线程通常叫做程序的主线程

子线程 : 因为程序是开始时就执行的 , 如果你需要再创建线程 , 那么创建的线程就是这个主线程的子线程

主线程的重要性体现在两方面 : 1. 是产生其他子线程的线程 2. 通常它必须最后完成执行比如执行各种关闭操作

(2)

join : 阻塞调用程序 , 直到调用join () 方法的线程执行结束, 才会继续往下执行
在这里插入图片描述

阶段二:线程通信

1.互斥锁

在多线程中 , 所有变量对于所有线程都是共享的 , 因此 , 线程之间共享数据最大的危险在于多个线程同时修改一个变量 , 那就乱套了 , 所以我们需要互斥锁 , 来锁住数据。

2.线程间全局变量的共享

在这里插入图片描述提示!因为线程属于同一个进程,因此它们之间共享内存区域。因此全局变量是公共的。

3.共享内存间存在竞争问题

from threading import Thread

x = 0
n =1000000
def a(n):
    global x
    for i in range(n):
        x += 1
def b(n):
    global x
    for i in range(n):
        x -= 1

if __name__ == '__main__':
    a = Thread(target=a,args = (n,))
    b = Thread(target=b,args = (n,))
    a.start()
    b.start()
    a.join()
    b.join()
    print(x)

提示! 如果1000000不能出现效果可以继续在后面加0
你会发现这个结果千奇百怪!!!

4.使用锁来控制共享资源的访问

下面引入互斥锁
在多线程中 , 所有变量对于所有线程都是共享的 ,因此 ,线程之间共享数据最大的危险在于多个线程同时修改一个变量 , 那就乱套了 , 所以我们需要互斥锁 , 来锁住数据。
只要我们操作全局变量的时候,就在操作之前加锁,再操作完之后解锁,就解决了这个资源竞争的问题!!!

在这里插入图片描述

5.队列的基本概念

一个入口,一个出口先入先出(FIFO)

队列操作一览:

入队: put(item)

出队: get()

测试空: empty()

测试满: full()

队列长度: qsize()

任务结束: task_done()

等待完成: join()

注意:
get()等待任务完成,如果不加task_done()则不表示任务完成,只要加这句才表明完成。才会结束执行。
join就是阻塞,直到这个任务完成(完成的标准就是每次取出都task_done()了)

阶段三:线程池

1.池的概念

主线程: 相当于生产者,只管向线程池提交任务。

         并不关心线程池是如何执行任务的。    

线程池: 相当于消费者,负责接收任务,

       并将任务分配到一个空闲的线程中去执行。         

           因此,并不关心是哪一个线程执行的这个任务。

2.线程池的简单实现

from threading import Thread
from queue import Queue
import time

class ThreadPool:
	
	def __init__(self,n):
		self.queue = Queue()
		for i in range(n):
			Thread(target = self.worker,daemon = True).start()
	
	def worker(self):
		while True:
			func,args,kwargs = self.queue.get()
			func(*args,*kwargs)
			self.queue.task_done()
	
	def apply_async(self,target,args = (),kwargs = {}):
		self.queue.put((target,args,kwargs))
	
	def join(self):
		self.queue.join()
	
def fun(x):
	print('hello 第%s次'%x)
	time.sleep(3)
	print('帅哥美女就给点赞啦!')

t = ThreadPool(2)
for i in range(10):
	t.apply_async(fun,args = (i,))
t.join()

3.python内置线程池

from multiprocessing.pool import ThreadPool
import time

pool = ThreadPool(2)       		   #创建两个线程
	
def funa(x,y):
    print('%s好好学习'%x)
    time.sleep(3)
    print('天天向上')

def funb(x,y):
    print('%shello'%x)
    time.sleep(3)
    print('world')

#我们这就是有一个线程池,里面有两个等待处理任务的线程,然后这两个函数就是两个任务,
#线程池里一个线程处理一个,所以会同时输出!如果多于两个任务就会执行等待sleep


pool.apply_async(funa,args = ('我们要————',2))   #将任务添加到线程池
pool.apply_async(funb,args = ('大家要————',4))

pool.close()       					  #close之后则无法向线程池提交任务

#内置线程池,自带守护线程,主线程结束,子线程也跟着结束
#所以需要加阻塞,否则主线程一结束,子线程也跟着结束,无输出
pool.join()          #在join之前可使用终止线程,直接终止线程pool:  pool.terminate()

print('这是程序的最后一行,执行到这里,主线程结束')

4.池的其他操作

操作一: close - 关闭提交通道,不允许再提交任务

操作二: terminate - 中止进程池,中止所有任务

发布了65 篇原创文章 · 获赞 50 · 访问量 3596

猜你喜欢

转载自blog.csdn.net/qq_44907926/article/details/104653842