• 并发多任务(线程、进程、协程)


    一、线程

    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)
    mutex锁

      将互斥锁加在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("
    拷贝进度为: %.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与send

      当函数运行到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()
    yield运行顺序

    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运行方法

      在函数中定义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     ])
    gevent运行方法
      g1 = gevent.spawn(function,arg())
      g1.join()
      monkey.patch_all()自动校正延时time.sleep()为gevent.sleep()
      gevent.joinall([gevent.spawn()])添加多个spawn

     四、总结(个人理解)

    1、节省资源方面:协程>线程>进程,程序稳定性方面则反之

    2、协程利用线程运行等待的时间,去运行其他任务,切换任务资源小

       线程资源一般,效率一般

       进程给线程分配CPU的资源,让线程各自运行任务,切换任务资源大,因此耗费资源最多

  • 相关阅读:
    phpcms 的getcache()函数
    git 上配置公钥
    linux 上git安装
    mac上php的扩展yaf安装
    Linux常用指令---grep(搜索过滤)
    mac virtualbox+vagrant安装
    nginx配置location及rewrite规则重写
    mac php环境搭建
    nginx.pid丢失问题
    git操作教程详解
  • 原文地址:https://www.cnblogs.com/ybxw/p/11111315.html
Copyright © 2020-2023  润新知