什么是异步及使用场景?

写代码过程中,经常会碰到,某一个函数,可能需要执行很久,才会返回,那么,我们现在让程序在这里死等着让它执行完成,很影响代码性能,因此,需要借用异步处理!比如如下demo

def my_func():
    demo()
    pass


def demo():
    # long time
    import time
    import random
    time.sleep(10 * random.randint(1,5))#IO密集型操作
    return 'Success or Faild'

如何使用异步,以及异步的返回结果如何进行回调?

异步的原理就是,这个时候,不再自己执行函数,把任务交出去,给其他人去执行,总之,原理就是我不再等你完事,我要干自己事情去了!

那么怎么交出去呢?

1.可以多开个线程交出去,使用装饰器(单机处理)

def async_demo(func):
    from threading import Thread
    def wrapper(*args, **kwargs):
        thr = Thread(target=func, args=args, kwargs=kwargs)
        thr.start()
    return wrapper


def my_func():
    demo()
    print('my_func todo')
    pass

@async_demo
def demo():
    # long time
    import time
    import random
    time.sleep(10 * random.randint(1,5))#IO密集型操作
    return 'Success or Faild'

2.可以交给redis内存,以队列形式,供其他进程或者线程去消耗(分布式处理,或者单机多进程处理)

代码请自行研究,这里暂不做举例,涉及代码较多(queue队列)

3.使用协程(单机单线程)

yield也起到挂起程序的作用

import time

def foo():
    print('Running in foo') #1
    yield
    time.sleep(3)
    print('Explicit context switch to foo again') #3
 
def bar():
    print('Explicit context to bar') #4
    yield
    time.sleep(3)
    print('Implicit context switch back to bar') #6
 
next(foo())
next(bar())
print('haha')

gevent

import gevent
def foo():
    print('Running in foo') #1
    gevent.sleep(2) #2
    print('Explicit context switch to foo again') #3
 
def bar():
    print('Explicit context to bar') #4
    gevent.sleep(1) #5
    print('Implicit context switch back to bar') #6
 
gevent.joinall([
    gevent.spawn(foo),
    gevent.spawn(bar),
])

 

注意:

虽然异步比较适用于大部分的等待时间较长的操作,但是作为python程序,因为有全局锁(GIL)的存在,即同一时刻只有一个线程在CPU中跑,所以,对于计算密集型操作,是不适合本机多开线程的,反而会影响执行速度!

关于网络、磁盘IO密集型和CPU密集型:

对于网络、磁盘IO来说,因为会有很多等待时间,比如,请求资源到等待返回资源这段时间(也叫IO等待),这个线程是啥事都干不了的,还不如让其他线程继续进行请求或作其他操作,这个时候多线程就有用了;

但是CPU密集型的操作来说:因为要持续跑CPU,这个线程实质上是基本没有休息时间的,因为在持续占用CPU进行操作,所以,这个时候,python多线程用处不大,还会因为频繁切换线程而耗费资源!