定时器、线程queue、进程池和线程池
1.定时器
指定n秒后,执行任务
1 from threading import Timer,current_thread 2 import os 3 4 5 def hello(): 6 print("%s hello, world"%os.getpid()) 7 print("%s hello, world"%current_thread().name) 8 9 10 t = Timer(3, hello) 11 t.start() # after 1 seconds, "hello, world" will be printed 12 print(os.getpid()) 13 print(current_thread()) 14 15 # 12376 16 # <_MainThread(MainThread, started 12008)> 17 # 12376 hello, world 18 # Thread-1 hello, world
2.线程queue
2.1 先进先出
1 import queue 2 3 q=queue.Queue() 4 q.put('first') 5 q.put('second') 6 q.put('third') 7 8 print(q.get()) 9 print(q.get()) 10 print(q.get()) 11 ''' 12 结果(先进先出): 13 first 14 second 15 third 16 '''
2.2 后进先出
1 import queue 2 3 q=queue.LifoQueue() 4 q.put('first') 5 q.put('second') 6 q.put('third') 7 8 print(q.get()) 9 print(q.get()) 10 print(q.get()) 11 ''' 12 结果(后进先出): 13 third 14 second 15 first 16 '''
2.3 优先级队列(开了会员就要先出来)
存储数据时可以设置优先级队列。数字越小(可以为负数),优先级越高,取出来的是一个元组形式。
里面put什么值就取出来什么值,只是优先级的问题。
1 import queue 2 3 q=queue.PriorityQueue() 4 #put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高 5 q.put((20,'a')) 6 q.put((10,'b')) 7 q.put((30,'c')) 8 9 print(q.get()) 10 print(q.get()) 11 print(q.get()) 12 ''' 13 结果(数字越小优先级越高,优先级高的优先出队): 14 (10, 'b') 15 (20, 'a') 16 (30, 'c') 17 '''
3.进程池和线程池
'''
1、什么时候用池:
池的功能是限制启动的进程数或线程数,
什么时候应该限制???
当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时
就应该用池的概念将开启的进程数或线程数限制在计算机可承受的范围内
2、同步vs异步
同步、异步指的是提交任务的两种方式
同步:提交完任务后就在原地等待,直到任务运行完毕后拿到任务的返回值,再继续运行下一行代码
异步:提交完任务(绑定一个回调函数)后根本就不在原地等待,直接运行下一行代码,等到任务有
返回值后会自动触发回调函数
'''
concurrent.futures 高度封装的异步调用接口
ProcessPoolExecutor 进程池 提供异步调用
ThreadPoolExecutor 线程池 提供异步调用
1 from socket import * 2 3 sever = socket(AF_INET,SOCK_STREAM) 4 sever.bind(("127.0.0.1",8080)) 5 sever.listen(5) 6 # 无法实现并发,建立一个连接,进入通信循环,直到通信循环结束 7 while True: 8 conn,addr = sever.accept() 9 while True: 10 try: 11 data = conn.recv(1024) 12 if len(data) == 0:break 13 conn.send(data.upper()) 14 except ConnectionResetError: 15 break 16 sever.close() 17 18 19 from socket import * 20 21 sever = socket(AF_INET,SOCK_STREAM) 22 sever.bind(("127.0.0.1",8080)) 23 sever.listen(5) 24 def task(conn): 25 while True: 26 try: 27 data = conn.recv(1024) 28 if len(data) == 0: break 29 conn.send(data.upper()) 30 except ConnectionResetError: 31 break 32 sever.close() 33 # 还是实现不了并发,只能实现串行 34 while True: 35 conn,addr = sever.accept() 36 task(conn) 37 38 from socket import * 39 from threading import Thread 40 41 sever = socket(AF_INET,SOCK_STREAM) 42 sever.bind(("127.0.0.1",8080)) 43 sever.listen(5) 44 def task(conn): 45 while True: 46 try: 47 data = conn.recv(1024) 48 if len(data) == 0: break 49 conn.send(data.upper()) 50 except ConnectionResetError: 51 break 52 sever.close() 53 54 # 启动一个子线程干通信的活 55 # 每建立一个连接就开启一个子线程,交给子线程干通信的活,可以实现并发 56 while True: 57 conn,addr = sever.accept() 58 59 t = Thread(target=task,args=(conn,)) 60 t.start() 61 62 from socket import * 63 from threading import Thread 64 65 def task(conn): 66 while True: 67 try: 68 data = conn.recv(1024) 69 if len(data) == 0: break 70 conn.send(data.upper()) 71 except ConnectionResetError: 72 break 73 sever.close() 74 75 # 将while循环放到函数下面,可以往里面传入ip,port和半连接池的最大限制数 76 # 这样做是已经实现并发了,但是如果有很多的客户请求,需要不停的建立线程数,电脑肯定是有上限的。 77 # python中的线程是操作系统的原生线程,需要操作系统来调度,同时开启太多线程,操作系统调度不过来。 78 # 限制线程数不是为了提高效率,是高并发情况下不得已而为之 79 def sever_func(ip,port,backlog = 5): 80 while True: 81 sever = socket(AF_INET,SOCK_STREAM) 82 sever.bind((ip, port)) 83 sever.listen(backlog) 84 print("start-------") 85 conn,addr = sever.accept() 86 87 t = Thread(target=task,args=(conn,)) 88 t.start() 89 90 if __name__ == '__main__': 91 sever_func("127.0.0.1",8080)
同步
同步:提交完任务后就在原地等待,直到任务运行完毕后拿到任务的返回值,再继续运行下一行代码
同步调用并不是真正意义上的串行,只是他的取值方式让程序变成了串行的工作方式。
1 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 2 import time 3 import os 4 5 6 def task(n): 7 print("%s is running"%os.getpid()) 8 time.sleep(5) 9 return n**2 10 11 # 默认是cpu的个数 12 # 如果直接在提交任务后拿到返回值就变成同步了 13 if __name__ == '__main__': 14 pool = ProcessPoolExecutor(4) 15 l = [] 16 for i in range(1,10): 17 future = pool.submit(task,i) 18 l.append(future) 19 # print(future) 20 # print(future.result()) 21 pool.shutdown(wait=True) 22 for m in l: 23 print(m.result())
异步
异步:提交完任务(绑定一个回调函数)后根本就不在原地等待,直接运行下一行代码,等到任务有
返回值后会自动触发回调函数
回调函数:parse会在futrue有返回值时立刻触发,并且将future当作参数传给parse
1 from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor 2 from threading import current_thread 3 import os 4 import time 5 import random 6 7 def task(n): 8 print('%s run...' %current_thread().name) 9 time.sleep(5) 10 return n**2 11 12 def parse(future): 13 time.sleep(1) 14 res=future.result() 15 print('%s 处理了 %s' %(current_thread().name,res)) 16 17 if __name__ == '__main__': 18 pool=ThreadPoolExecutor(4) 19 start=time.time() 20 for i in range(1,5): 21 future=pool.submit(task,i) 22 future.add_done_callback(parse) # parse会在futrue有返回值时立刻触发,并且将future当作参数传给parse 23 pool.shutdown(wait=True) 24 stop=time.time() 25 print('主',current_thread().name,(stop - start))
越是困难的事越要立即去做,这样收益才会最大!!!