统一进程内的队列(多线程)
import queue
queue.Queue() # 先进先出
queue.LifoQueue() # 后进先出(先进后出)
queue.PriorityQueue() 优先级队列
优先级队列 q = queue.PriorityQueue()
q.put() # 接收到的是一个元组类型的数据.
元组中第一个额参数是: 表示当前数据的优先级.
元组中第二个参数是: 需要存放到队列中的数据.
优先级的比较(首先保证整个队列中, 所有表示优先级的数据类型必须一致)
如果都是int, 比较数值大小(在ASCII码中只有0-9, 如果出现两位数字会先比较
第一位数, 如果第一位数相同在比较第二位, 如果第一位就比较出优先级, 后面
就不再继续比较.)
如果是str, 比较字符串的大小(从第一个字符的ASCII码开始比较)
from multiprocessing import Queue # 用于多进程对列, 就是专门用来做进程间通信的(IPC) import queue # 是用于统一进程内的队列, 不能做多进程之间的通信. # q = queue.Queue() # # 先进先出 # q.put(1) # q.put(2) # q.put(3) # print(q.get()) # print(q.get()) # print(q.get()) # # get()不需要传参数, # q1 = queue.LifoQueue() # # 线进后出 # q1.put(1) # q1.put(2) # q1.put(3)
# print(q1.get()) # print(q1.get()) # print(q1.get()) # # get()不需要传参数, q2 = queue.PriorityQueue() # 优先级输出 q2.put((1,'1')) q2.put((3,'3')) q2.put((2,'2')) # 传入的是一个元组 print(q2.get()) print(q2.get()) print(q2.get()) # get()不需要传参数 # 当表示优先级的第一个元素为一位数数字时, 会直接比较. 当是两位数字的时候 # 会先比较第一位数, 如果比较出大小,将停止比较进行输出, 否则继续比较下一位.
多线程:
threading模块可以创建多个线程,不过由于GIL锁的存在,Python在多线程里面其实是快速切换
多线程与多进程的对比:
from threading import Thread from multiprocessing import Process import time def func_daemon(): time.sleep(3) # print('这是守护进程') print('这是守护线程') def func(): time.sleep(1) # time.sleep(5) # print('这是普通进程') print('这是普通线程') # 守护进程是随着父进程的代码执行结束而结束 # 守护线程不是随着父线程的代码执行结束而结束 # 守护线程是随着父线程的执行结束而结束 if __name__ == '__main__': t = Thread(target=func_daemon,) t.daemon = True t.start() t1 = Thread(target=func, ) t1.start() print('这里是父线程') time.sleep(20) # p = Process(target=func_daemon, ) # p.daemon = True # p.start() # p1 = Process(target=func, ) # p1.start() # print('这是父进程')
多线程的条件:
from threading import Condition,Thread import time def func(con,i): con.acquire()# 主线程和10个子线程都在抢夺递归锁的一把钥匙。 # 如果主线程抢到钥匙,主线程执行while 1,input,然后notify发信号,还钥匙。但是,此时如果主线程执行特别快 # 极有可能接下来主线程又会拿到钥匙,那么此时哪怕其他10个子线程的wait接收到信号,但是因为没有拿到钥匙,所以其他子线程还是不会执行 con.wait() print('第%s个线程执行了'%i) con.release() con = Condition() for i in range(10): t = Thread(target=func,args = (con,i)) t.start() while 1: # print(123) con.acquire() num = input('>>>') con.notify(int(num)) con.release() time.sleep(0.5) # 条件 涉及 4个方法: # con.acquire() # con.release() # con.wait() # 假设有一个初始状态为False,阻塞。一旦接受到notify的信号后,变为True,不再阻塞 # con.notify(int) 给wait发信号,发int个信号,会传递给int个wait,让int个线程正常执行
多线程之条件:
from threading import Condition,Thread # Thread 美 /θrɛd/ # Condition 美 /kən'dɪʃən/ import time def func(con,i): con.acquire()
# 主线程和10个子线程都在抢夺递归锁的一把钥匙。 # 如果主线程抢到钥匙,主线程执行while 1,input,然后notify发信号,还钥匙。 # 但是,此时如果主线程执行特别快 # 极有可能接下来主线程又会拿到钥匙,那么此时哪怕其他10个子线程的wait接收到信号, # 但是因为没有拿到钥匙,所以其他子线程还是不会执行
con.wait() print(i) con.release() con = Condition() for i in range(10): Thread(target=func,args=(con,i)).start() while 1: con.acquire() num = int(input(">>>")) con.notify(num) con.release() time.sleep(0.5) # 条件判断涉及4个方法: # con.acquire() # 拿钥匙锁门 # con.release() # 还钥匙开门 # con.notify() # 给wait 发int个信号, 会传递给int个wait, 让int个线程正常执行. # con.wait() # 假设有一个初始状态为False, 阻塞.一旦接收到notify的信号,变为Ture, 不再阻塞.
线程池相关内容:
概念:
在一个池子中, 方固定数量的线程, 这些线程等待任务, 一旦有任务来, 就有线程自发的去执行任务
# concurrent.futures 这个模块是异步调用机制. 其提交任务都是用submit
# for + submit 多个任务的提交.
# shutdown 是等效于Pool 中的 close + join. 是指不逊于再继续相持中增加任务, 然后让父进程(线程)等待
# 如何把多个任务扔进池中:
要么使用 for + submit 的方式去提交多个任务.
要么直接使用map(func, iterable) 方式去提交多个任务
不同的方式提交多个任务(for + submit 或者 map), 拥有不同的那结果的方式,
如果是for + submit 的方式提交任务, 那结果用result方法.
如果是map的方式提交任务, 结果是一个生成器, 采用__next__的方式去拿结果.
线程池中多任务提交:
方法一
from concurrent.futures import ThreadPoolExecutor
# concurrent.futures 这个模块是异步调用的机制.
# 其提交任务都是用submit
# for + submit 多个任务提交
import time def func(num): sum = 0 for i in range(num): sum += i ** 2 print(sum) t = ThreadPoolExecutor(20) start = time.time() t.map(func,range(1000))# 提交多个任务给池中。 等效于 for + submit t.shutdown() print(time.time() - start)
多任务提交方法二
from concurrent.futures import ThreadPoolExecutor # concurrent.futures 这个模块是异步调用的机制. # 其提交任务都是用submit # for + submit 多个任务提交 import time def func(num): sum = 0 for i in range(num): sum += i ** 2 print(sum) t = ThreadPoolExecutor(20) start = time.time() for i in range(20):
t.submit(func, i)
t.shutdown()
print(time.time() - start)
进程池线程池效率比较:
# 结果:针对计算密集的程序来说 # 不管是Pool的进程池还是ProcessPoolExecutor()的进程池,执行效率相当 # ThreadPoolExecutor 的效率要差很多 # 所以 当计算密集时,使用多进程。
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from multiprocessing import Pool import time # def func(num): # sum = 0 # for i in range(num): # for j in range(i): # for x in range(j): # sum += x ** 2 # print(sum) # if __name__ == '__main__': # pool D的进程池效率演示: # p = Pool(5) # 定义的进程池中的进程数为CPU核数+1 # start = time.time() # for i in range(100): # p.apply_async(func, args=(i,)) # p.close() # p.join() # print(time.time() - start) # concurrent.futures中的多进程效率 # p1 = ProcessPoolExecutor(5) # start1 = time.time() # for i in range(100): # p1.submit(func, i) # p1.shutdown() # print(time.time() - start1) # 线程的效率: # p2 = ThreadPoolExecutor(20) # start2 = time.time() # for i in range(1000): # p2.submit(func,i) # p2.shutdown() # print(time.time() - start2) # 结果:针对计算密集的程序来说 # 不管是Pool的进程池还是ProcessPoolExecutor()的进程池,执行效率相当 # ThreadPoolExecutor 的效率要差很多 # 所以 当计算密集时,使用多进程。
进程池返回值:
from concurrent.futures import ThreadPoolExecutor
import time
# def func(num):
# sum = 0
# for i in range(num):
# sum += i**2
# return sum
#
# if __name__ == '__main__':
# q = ThreadPoolExecutor(20)
# 下列代码是用for + submit提交多个任务的方式,对应拿结果的方法是result
# l = []
# for i in range(1000):
# f = q.submit(func,i)
# l.append(f)
# q.shutdown()
# [print(i.result()) for i in l]
# 在Pool进程池中拿结果,是用get方法。 在ThreadPoolExecutor里边拿结果是用result方法
# q1 = ThreadPoolExecutor(20)
# 下列代码是用map的方式提交多个任务,
# 对应 拿结果的方法是__next__() 返回的是一个生成器对象
# f = q1.map(func,range(1000))
# q1.shutdown()
# print(f.__next__())
# print(f.__next__())
# print(f.__next__())
回调函数:
from concurrent.futures import ProcessPoolExecutor # 不管是ProcessPoolExecutor的进程池 还是Pool的进程池,回调函数都是父进程调用的。 import os import requests def func(num): sum = 0 for i in range(num): sum += i ** 2 return sum def call_back_fun(res): # print(res.result(),os.getpid()) print(os.getpid()) if __name__ == '__main__': print(os.getpid()) t = ProcessPoolExecutor(20) for i in range(1000): t.submit(func,i).add_done_callback(call_back_fun) t.shutdown()