一、线程
1、一般多线程
1 import time 2 import threading 3 4 5 def sing(): 6 for i in range(5): #调用Thread不会创建线程, 7 print("----test----") #调用Thread创建的实例对象start会创建 8 time.sleep(1) 9 10 def main(): 11 print(threading.enumerate()) #调用Thread之前打印 12 t1 = threading.Thread(target=sing) #调函数名,告诉函数在哪 13 print(threading.enumerate()) #调用Thread之后打印 14 t1.start() 15 print(threading.enumerate()) #调用start之后打印 16 17 18 if __name__ == '__main__': 19 main()
target指定线程去哪执行代码,args指定将来调用传递的数据
当线程t1.start()运行时,会先运行下一行代码,因此运行结果为:
[<_MainThread(MainThread, started 139815265257216)>] [<_MainThread(MainThread, started 139815265257216)>] ----test---- [<_MainThread(MainThread, started 139815265257216)>, <Thread(Thread-1, started 139815239530240)>] ----test---- ----test---- ----test---- ----test----
2、封装多线程为类
1 import threading 2 import time 3 4 5 class MyThread(threading.Thread): 6 def run(self): 7 for i in range(3): 8 time.sleep(1) 9 msg = "I'm "+self.name+'@'+str(i) 10 print(msg) 11 self.login() 12 13 def login(self): 14 print("登陆") 15 16 17 if __name__ =='__main__': 18 t = MyThread() 19 t.start()
MyThread会先自动调用run方法,再通过run方法引入其他函数self.funtion
3、防止CPU资源竞争-互斥锁
1 #创建互斥锁,默认没有上锁 2 mutex = threading.Lock() 3 4 def test1(temp): 5 global g_num 6 #上锁 如果之前没有被上锁,那么此时上锁成功 7 #如果之前上锁了,那么此时会被堵塞,直到解锁 8 mutex.acquire() 9 for i in range(temp): 10 g_num += 1 11 #解锁 12 mutex.release() 13 print("---in test1 temp=%d---" % g_num)
将互斥锁加在for循环内会影响过程变化,执行顺序不同
二、进程
1、内容
进程是资源分配单位,线程是调度单位,线程比进程节省资源;
进程:工厂流水线,线程:工人,线程依赖于进程
1 import multiprocessing 2 from threading import Thread 3 import time 4 5 6 def test1(): 7 while True: 8 print("1------") 9 time.sleep(1) 10 11 def test2(): 12 while True: 13 print("2------") 14 time.sleep(1) 15 16 def main(): 17 t1 = multiprocessing.Process(target=test1) 18 t2 = multiprocessing.Process(target=test2) 19 t1.start() 20 t2.start() 21 22 if __name__ == "__main__": 23 main()
2、队列
先入先出原则,使用put()方法写入,get()方法取出
1 import multiprocessing 2 import time 3 4 5 def download(q): 6 data = [11, 22, 33, 44] 7 #向队列中写入数据 8 for temp in data: 9 q.put(temp) 10 print('已下载完并存入队列') 11 12 def analysis_data(q): 13 '''数据处理''' 14 #从队列中获取数据 15 waitting_analysis_data = list() 16 while True: 17 data = q.get() 18 print(data) 19 waitting_analysis_data.append(data) 20 if q.empty(): 21 break 22 print(waitting_analysis_data) 23 24 25 def main(): 26 #1.创建一个队列 27 q = multiprocessing.Queue() 28 29 #2.创建多个进程,将队列引用当做实参进行传递 30 p1 =multiprocessing.Process(target=download, args=(q,)) 31 print('---p1------') 32 p2 =multiprocessing.Process(target=analysis_data, args=(q,)) 33 print('---p2------') 34 p1.start() 35 36 print('---p1s-----') 37 p2.start() 38 print('---p2s-----') 39 40 41 if __name__ =='__main__': 42 main()
3、进程池
from multiprocessing import Pool import os,time,random def worker(msg): t_start = time.time() print("%S开始执行,进程号为%d" % (msg,os.getid())) #random.random随机生成0~1质检的浮点数 time.sleep(random.random()*2) t_stop = time.time() print(msg,"执行完毕,耗时%0.2f" % (t_stop-t_start)) po = Pool(3) #定义一个进程池,最大进程数3 for i in range(0,10): #Pool().apply_async(要掉用的目标,(传递给目标的参数元祖,)) #每次循环会用空闲出来的子进程去调用目标 po.apply_async(worker,(i,)) print("---start---") po.close() #关闭进程池,关闭后PO不再接受新的请求 po.join() #等待PO种的子进程执行完,必须在close之后 print('---end----')
4、显示进度
1 import os 2 from multiprocessing import Pool 3 import multiprocessing 4 from multiprocessing import Manager 5 6 7 def copy_file(q,file_name, old_folder, new_folder): 8 #完成文件的复制 9 print("模拟copy文件:从%s复制%s到%s" % (old_folder, file_name, new_folder)) 10 older_f = open(old_folder + "/" + file_name, "rb") 11 content = older_f.read() 12 older_f.close() 13 14 new_f = open(new_folder + "/" +file_name, "wb") 15 new_f.write(content) 16 new_f.close() 17 #如果拷贝完文件,那么向队列写入一个消息表示完成 18 q.put(file_name) 19 20 21 def main(): 22 #1.获取用户要copy的文件夹名字 23 old_folder = input("请输入文件夹名字:") 24 25 #2.创建一个新的文件夹 26 try: 27 new_folder = old_folder + "[复件]" 28 os.mkdir(new_folder) 29 except: 30 pass 31 32 #3.获取文件夹的所有待copy文件名字 33 file_names = os.listdir(old_folder) 34 print(file_names) 35 36 #4.创建进程池 37 po = Pool(5) 38 #6.创建一个队列 39 q = Manager().Queue() 40 41 #5.向进程池中添加copy文件的任务 42 for file_name in file_names: 43 po.apply_async(copy_file, args=(q, file_name, old_folder, new_folder)) 44 45 46 #复制文件夹中的文件,到新文件夹中的文件去 47 48 po.close() 49 # po.join() 50 all_file_num = len(file_names) 51 copy_num = 0 52 while True: 53 file_name = q.get() 54 #print("已经完成copy: %s" % file_name) 55 copy_num+=1 56 print("\r拷贝进度为: %.2f %%" % (copy_num*100/all_file_num),end="") 57 if all_file_num == copy_num: 58 break 59 60 print() 61 62 63 if __name__ == "__main__": 64 main()
三、协程
1、迭代与迭代器
1 from collections import Iterable 2 from collections import Iterator 3 import time 4 5 class Classmate(object): 6 def __init__(self): 7 self.names = list() 8 self.current_num = 0 9 def add(self, name): 10 self.names.append(name) 11 12 def __iter__(self): 13 '''如果想要一个对象称为一个 可以迭代的兑现,可以使用for,那么必须实现__iter__方法''' 14 return self 15 #1.判断xxx.obj是否可以迭代 16 #2.调用iter函数得到xxx_obj的_iter_方法返回值 17 #3.返回值是一个迭代器 18 def __next__(self): 19 if self.current_num < len(self.names): 20 ret = self.names[self.current_num] 21 self.current_num += 1 22 return ret 23 else: 24 raise StopIteration 25 26 classmate = Classmate() 27 classmate.add("老王") 28 classmate.add("老二") 29 classmate.add("张三") 30 31 print(iter(classmate)) 32 print("判断classmate是否是可以迭代的对象:",isinstance(classmate, Iterable)) 33 #classmate_iterator = iter(classmate) 34 #print("判断classmate是否是可以迭代的对象:",isinstance(classmate_iterator, Iterable)) 35 #print(next(classmate_iterator)) 36 37 for name in classmate: 38 print(name) 39 time.sleep(1)
2、生成器与传递值
1 def create_num(all_num): 2 a, b = 0, 1 3 current_num = 0 4 while current_num < all_num: 5 ret = yield a #第一次暂停,返回a = 0给next(obj),send值传递给ret 6 print('>>>ret>>>', ret) 7 a, b = b, a+b 8 current_num += 1 9 10 obj = create_num(10) 11 12 ret = next(obj) 13 print(ret) 14 15 ret = obj.send('hahhah') #hahha传递给yield a 16 print(ret)
当函数运行到yield时,函数先暂停运行,并跳过该函数继续往下运行直到遇到next()
1 import time 2 3 4 def task_1(): 5 while True: 6 print("----1----") 7 time.sleep(0.1) 8 yield 9 10 def task_2(): 11 while True: 12 print("----2----") 13 time.sleep(0.1) 14 yield 15 16 def main(): 17 t1 = task_1() 18 t2 = task_2() 19 #先运行t1,当遇到yield时,返回到24行 20 #然后执行t2,遇到yield时切换到t1中 21 #t1/t2交替运行实现多任务,并发协程 22 while True: 23 next(t1) 24 next(t2) 25 26 27 if __name__ =="__main__": 28 main()
3、greenlet
1 from greenlet import greenlet 2 import time 3 4 def test1(): 5 while True: 6 print("---1---") 7 gr2.switch() 8 time.sleep(0.5) 9 10 def test2(): 11 while True: 12 print("---2---") 13 gr1.switch() 14 time.sleep(0.5) 15 16 gr1 = greenlet(test1) 17 gr2 = greenlet(test2) 18 19 gr1.switch()
在函数中定义greenlet().switch(),当主函数switch()时开始运行,来回切换
4、gevent
1 import gevent 2 from gevent import monkey 3 import time 4 5 monkey.patch_all() 6 7 def f1(n): 8 for i in range(n): 9 print(gevent.getcurrent(),i) 10 time.sleep(0.5) 11 def f2(n): 12 for i in range(n): 13 print(gevent.getcurrent(),i) 14 time.sleep(0.5) 15 16 def f3(n): 17 for i in range(n): 18 print(gevent.getcurrent(),i) 19 time.sleep(0.5) 20 21 print("---1----") 22 g1 = gevent.spawn(f1, 5) 23 24 print("---2----") 25 g2 = gevent.spawn(f2, 5) 26 27 print("---3----") 28 g3 = gevent.spawn(f3, 5) 29 30 print("---4----") 31 32 g1.join() 33 g2.join() 34 g3.join() 35 36 gevent.joinall([ 37 gevent.spawn(f1,5) 38 gevent.spawn(f2,5) 39 gevent.spawn(f3,5) 40 ])
四、总结(个人理解)
1、节省资源方面:协程>线程>进程,程序稳定性方面则反之
2、协程利用线程运行等待的时间,去运行其他任务,切换任务资源小
线程资源一般,效率一般
进程给线程分配CPU的资源,让线程各自运行任务,切换任务资源大,因此耗费资源最多