线程(下)

一、队列

1.1先进先出

import queue  #导入队列模块

q = queue.Queue(3)  #实例化一个队列对象,允许在里面放入3个数据
q.put(123)
q.put('you are my sunshine')
q.put([1,2,3,4])

print(q.get())
print(q.get())
print(q.get())

'''
123
you are my sunshine
[1, 2, 3, 4]
'''

1.2先进后出(堆栈)

q = queue.LifoQueue()   #实例化一个队列,这个队列的原则是先进后出
q.put(123)
q.put('you are my sunshine')
q.put([1,2,3,4])

print(q.get())
print(q.get())
print(q.get())

'''
[1, 2, 3, 4]
you are my sunshine
123
'''

1.3 按优先级进出

q= queue.PriorityQueue(3)  #实例化一个优先级输出数据的队列的对象
q.put((1,'A'))   #括号里面是一个元祖,通常这个元祖的第一个值是int类型
q.put((2,'B'))
q.put((3,'C'))

print(q.get())  #(1, 'A')  先输出优先级高的


q= queue.PriorityQueue(3)
q.put((1,'emmm'))   #括号里面是一个元祖
q.put((1,'aaaa'))
q.put((3,'emmm'))

print(q.get())  #(1, 'aaaa')   当前面的数字一样时,后面的字符串是按照Ascall码排

二、定时器


import time
from threading import Thread,Timer

def task():
    print('线程开始')
    time.sleep(1.5)
    print('线程结束')

t = Timer(3,task)   #3秒之后开启一个线程,也就是说3秒之后打印出来了子线程中的内容
t.start()

三、线程池与进程池


​ 池的功能是限制进程数或线程数,当并发的任务数远远大于计算机所能承受的范围,即无法开启过多的任务数,我们就应该考虑限制进程数或者线程数,从而保证服务器不崩。

3.1 线程池

from concurrent.futures import ThreadPoolExecutor
from threading import currentThread
import time

def task(i):
    time.sleep(1.5)
    print(f"{currentThread().name}在执行任务{i+1}")
    return i**2

if __name__ == '__main__':
    fu_list = []
    pool = ThreadPoolExecutor(4)  #规定线程池有是个线程
    for i in range(20):  #模拟20个线程,task要做20次,4个线程负责做这个事情
        future = pool.submit(task,i)   #for循环一次,提交一次
        fu_list.append(future)   #先把提交的数据意义放到这个列表里面
    pool.shutdown()   # 关闭池的入口,不让你往里面再放东西
    for fu in fu_list:  #依次循环列表里面的值
        print(fu.result())  #打印返回值

'''
ThreadPoolExecutor-0_1在执行任务2
ThreadPoolExecutor-0_0在执行任务1
ThreadPoolExecutor-0_3在执行任务4
ThreadPoolExecutor-0_2在执行任务3

ThreadPoolExecutor-0_1在执行任务6
ThreadPoolExecutor-0_0在执行任务5
ThreadPoolExecutor-0_2在执行任务7
ThreadPoolExecutor-0_3在执行任务8
'''
.......

3.2 进程池

from concurrent.futures import ProcessPoolExecutor
from multiprocessing import current_process
import time

def task(i):
    time.sleep(1)
    print(f"{current_process().name}在执行任务{i+1}")
    time.sleep(1)
    return i**2

if __name__ == '__main__':
    fu_list = []
    pool = ProcessPoolExecutor(4)  #规定进程池有是个线程
    for i in range(20):  #模拟20个进程,task要做20次,4个进程负责做这个事情
        future = pool.submit(task,i)   #for循环一次,提交一次
        fu_list.append(future)   #先把提交的数据意义放到这个列表里面
    pool.shutdown()   # 关闭池的入口,不让你往里面再放东西
    for fu in fu_list:
        print(fu.result())
        
'''
SpawnProcess-1在执行任务1
SpawnProcess-2在执行任务2
SpawnProcess-3在执行任务3
SpawnProcess-4在执行任务4

SpawnProcess-1在执行任务5
SpawnProcess-2在执行任务6
SpawnProcess-3在执行任务7
SpawnProcess-4在执行任务8
.......
'''

四、提交任务的两种方式


4.1 同步

提交了一个任务,必须等任务执行完 (拿到返回值)才能执行下一行代码

import os
import time
import random
from multiprocessing import Process

def work(n):
    print(f'{n}: {os.getpid()} is running' )
    time.sleep(random.randint(1,3))
    print('%s:%s is done' %(n,os.getpid()))

if __name__ == '__main__':
    for i in range(3):  #这种就是同步了
        p=Process(target=work,args=(i,))
        p.start()

4.2 异步

提交了一个任务,不需要等任务执行完 (拿到返回值)才能执行下一行代码,就可以直接执行下一行

from concurrent.futures import ProcessPoolExecutor
from multiprocessing import current_process
import time

def task(i):
    time.sleep(1)
    print(f"{current_process().name}在执行任务{i+1}")
    time.sleep(1)
    return i**2

def parse(future):
    print(future.result())

if __name__ == '__main__':
    fu_list = []
    pool = ProcessPoolExecutor(4)  #规定进程池有是个线程
    for i in range(20):  #模拟20个进程,task要做20次,4个进程负责做这个事情
        future = pool.submit(task,i)   #for循环一次,提交一次
        future.add_done_callback(parse)
        # 为当前任务绑定了一个函数,在当前任务执行结束的时候会触发这个函数,
        # 会把future对象作为参数传给函数
        # 这个称之为回调函数,处理完了回来就调用这个函数. 
原文地址:https://www.cnblogs.com/lulingjie/p/11557349.html