python-多任务之线程、进程、协程


并发:假的多任务
并行:真的多任务

一、线程

import threading
def test01():
    while true:
        print("----1----")
def test02():
    while true:
        print("----2---)
def main():
    t1 = threading.Thread(target = test01)
    t2 = threading.Thread(target = test02)
    t1.start()
    t2.start()
if __name__ == "__main__"
    main()

1、Threading模块下的enumerate类
查看程序中所有的线程数的,返回的是一个元组
线程的运行是没有先后顺序的
2、如果创建Thread时执行的函数,运行结束,子线程也相应结束
3、当调用Thread不会创建线程,只有调用Thread创建出来对象的start方法的时候才会创建线程并且让这个线程进行工作
4、多线程共享全局变量
5、互斥锁   解决资源竞争的问题
申明互斥锁 mutex = threading.Lock()
上锁          mutex.acquire()
解锁         mutex.release()

二、进程

Import multiprocessing
def test01():
    while true:
        print("----1----")
def test02():
    while true:
        print("----2---)
def main():
    t1 = multiprocessing.Process(target = test01)
    t2 = multiprocessing.Process(target = test02)
    t1.start()
    t2.start()
if __name__ == "__main__"
    main()

1.进程和线程的区别
先有进程才有线程,没有进程就不会有线程
进程是资源分配的单位,线程是操作系统调度的单位
线程实现多任务需要很少的资源
进程实现多任务需要比较多的资源    
进程之间是互相独立的,线程之间共享全局变量
三、进程间的通信
queue 队列  先进先出
       栈  先进后出

三、协程

1、迭代器  

from collections import Iterable
from collections import Iterator
import time

class Dog(object):


    def __init__(self):
        self.names = list()


    def add(self, name):
        self.names.append(name)
 
    
    def __iter__(self):
        return Erha(self)
        

class Erha(object):
  

    def __init__(self, obj):
        self.obj = obj 
        self.count = 0

    def __iter__(self):
        pass
    

    def __next__(self):
        if self.count < len(self.obj.names):
            ret =  self.obj.names[self.count]
            self.count += 1
            return ret
        else:
            raise StopIteration

dog = Dog()
dog.add("大黄")
dog.add("菠菜")
dog.add("咖啡")
print("dog对象是否是一个可迭代对象:", isinstance(dog, Iterable))
dog_iter = iter(dog)
print("dog对象是否是一个迭代器:", isinstance(dog_iter, Iterator))

for name in dog:
    print(name)
    time.sleep(1)

2、生成器
生成器是一种特殊的迭代器。
创建生成器的第一种方式:
列表:
L = [x*2 for x in range(5)] # 返回的是生成的数据
生成器:
G = (x*2 for x in range(5)) # 返回的是生成数据的方法即对象,节省空间
for i in G:
    print(i)
创建生成器的第二种方式:
如果在调用一个函数的时候发现有yield,则不是在调用函数,而是在创建一个生成器对象
每从yield取一次数据,则程序停留在yield后,数据不会丢失
例:使用生成器完成fibonacci数列:

def main(all_count):
    a, b = 0, 1
    count = 0

    while count < all_count:
        yield a
        a, b = b, a + b
        count += 1
if __name__ == "__main__":
    obj = main(10)
    for i in obj:
        print(i)

例:使用yield完成多任务

import time
def task1():
    while True:
        print("-----1-----")
        time.sleep(0.1)
        yield
def task2():
    while True:
        print("-----2-----")
        time.sleep(0.1)
        yield
def main():
    t1 = task1()
    t2 = task2()
    while True:
        next(t1)
        next(t2)
if __name__ == "__main__":
    main()

例:使用greenlet实现多任务

from greenlet import greenlet
import time
def task1():
    while True:
        print("-----1-----")
        t2.switch()
        time.sleep(0.5)
def task2():
    while True:
        print("-----2-----")
        t1.switch()
        time.sleep(0.5)
t1 = greenlet(task1)
t2 = greenlet(task2)
t1.switch()


例:使用gevent完成多任务

import gevent
from gevent import monkey
import time
# 将程序中的耗时操作换成自己实现的方式,而非gevent中的耗时方法
monkey.patch_all()
def task1():
    while True:
        print(gevent.getcurrent(), "-----1-----")  # gevent.getcurrent()获取当前打印的对象
        # gevent.sleep(0.1)
        time.sleep(0.1)
def task2():
    while True:
        print(gevent.getcurrent(), "-----2-----")
        # gevent.sleep(0.1)
        time.sleep(0.1)
# g1 = gevent.spawn(task1)
# g2 = gevent.spawn(task2)
# g1.join()
# g2.join()
gevent.joinall([
    gevent.spawn(task1),
    gevent.spawn(task2)
])


总结:greenlet、gevent底层都是通过yield实现,只不过是对yield的一次封装,推荐使用gevent

总结:
1、进程是资源分配的单位
2、线程是操作系统调度的单位
3、进程切换需要的资源很大,效率很低
4、线程切换需要的资源一般,效率一般(在不考虑GIL的情况下)
5、协程切换任务资源很小,效率高
6、多进程、多线程根据CPU核数不一样可能是并行的,但是协程是在一个线程中,所以是并发
 

猜你喜欢

转载自blog.csdn.net/weixin_44079370/article/details/108306792
今日推荐