关于同步异步程序的小示例

先说说基本概念,什么是同步异步


同步:

所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。

异步:

将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。

同步,是所有的操作都做完,才返回给用户结果。即写完数据库之后,在相应用户,用户体验不好。

异步,不用等所有操作等做完,就相应用户请求。即先相应用户请求,然后慢慢去写数据库,用户体验较好。 

举些栗子:

代码一

# -*- coding: utf-8 -*-
"""
    :author: zhangfq
    :order: 同步程序示例
"""

def reqA():
    print('开始执行reqA')
    print('结束执行reqA')

def reqB():
    print('开始执行reqB')
    print('结束执行reqB')

def main():
    reqA()
    reqB()

if __name__ == '__main__':
    main()

这个同步代码会输出:

    开始执行reqA
    结束执行reqA
    开始执行reqB
    结束执行reqB

代码二 

# -*- coding: utf-8 -*-
"""
    :author: zhangfq
    :order: 异步示例-通过回调函数实现
"""
import time
import threading

def longIO():

    def run():
        print('开始执行耗时任务')
        time.sleep(5)
        print('结束耗时任务')

    threading.Thread(target=run).start()

def reqA():
    print('开始执行reqA')
    longIO()
    print('结束执行reqA')

def reqB():
    print('开始执行reqB')
    time.sleep(2)
    print('结束执行reqB')

def main():
    reqA()
    reqB()

if __name__ == '__main__':
    main()
这个异步代码会输出:
    开始执行reqA
    开始执行耗时任务
    结束执行reqA
    开始执行reqB
    结束执行reqB
    结束耗时任务

说说差别

当上面的代码一中可以体现同步的思想,但是当我们在reqA中加入耗时任务时,整个程序会通过先执行reqA的代码,执行完后再继续执行reqB的代码,对于用户体验是相当的差,我们可以修改下代码,看看实现效果:

代码三

    # -*- coding: utf-8 -*-
"""
    :author: zhangfq
    :order: 同步示例2
"""
import time


def reqA():
    print('开始执行reqA')
    time.sleep(5)
    print('结束执行reqA')

def reqB():
    print('开始执行reqB')
    time.sleep(2)
    print('结束执行reqB')

def main():
    reqA()
    reqB()

if __name__ == '__main__':
    main()

将会输出:
    开始执行reqA
    等待5秒
    结束执行reqA
    开始执行reqB
    等待2秒
    结束执行reqB
总共需要7秒

回看下代码二,我们可以发现代码二需要执行浪费程度远远小于代码三。 这也很好的说明同步与异步的优劣

怎样获取异步函数返回的结果呢

同步获取的方法相当简单并感觉到羞耻:

代码四

# -*- coding: utf-8 -*-
"""
    :author: zhangfq
    :order: 同步示例2
"""
import time

def longIO():
    print('开始执行耗时任务')
    time.sleep(5)
    print('结束耗时任务')
    return "zhang"

def reqA():
    print('开始执行reqA')
    res = longIO()
    print('接收到的值:', res)
    print('结束执行reqA')

def reqB():
    print('开始执行reqB')
    time.sleep(2)
    print('结束执行reqB')

def main():
    reqA()
    reqB()

if __name__ == '__main__':
    main()

执行程序不统计其他,花费了7秒的时间

那么同步的获取返回数据该怎么修改呢?

代码五

# -*- coding: utf-8 -*-
"""
    :author: zhangfq
    :order: 异步示例-通过回调函数实现
"""
import time
import threading

def longIO(callback):
    def run(cb):
        print('开始执行耗时任务')
        time.sleep(5)
        print('结束耗时任务')
        cb('zhang')
    threading.Thread(target=run, args=(callback,)).start()

def func(data):
    print('执行回调函数')
    print('接收到的值:', data)
    print('结束回调函数')

def reqA():
    print('开始执行reqA')
    longIO(func)
    print('结束执行reqA')

def reqB():
    print('开始执行reqB')
    time.sleep(2)
    print('结束执行reqB')

def main():
    reqA()
    reqB()

if __name__ == '__main__':
    main()

开始执行reqA
开始执行耗时任务
结束执行reqA
开始执行reqB
结束执行reqB
结束耗时任务
执行回调函数
接收到的值: zhang
结束回调函数

这个程序化肥了5秒时间,并通过回调函数方式实现获取返回值

除了通过回调的方法,我们还可以通过协程进行实现异步

协程方法实现异步

代码六

# -*- coding: utf-8 -*-
"""
    :author: zhangfq
    :order: 异步示例-通过回调函数实现
"""
import time
import threading

gen = None

def longIO():
    def run():
        print('开始执行耗时任务')
        time.sleep(5)
        try:
            global gen
            gen.send('zhang')
        except:
            pass
        print('结束耗时任务')
    threading.Thread(target=run).start()


def reqA():
    print('开始执行reqA')
    res = yield longIO()
    print('接收到的值:', res)
    print('结束执行reqA')

def reqB():
    print('开始执行reqB')
    time.sleep(2)
    print('结束执行reqB')

def main():
    global gen
    gen = reqA()
    next(gen)
    reqB()

if __name__ == '__main__':
    main()



    开始执行reqA
    开始执行耗时任务
    开始执行reqB
    结束执行reqB
    接收到的值: zhang
    结束执行reqA
    结束耗时任务

代码六存在两个问题?

(1)reqA不能想reqB那样调用,只能作为生成器

(2)多了个gen全局变量问题

优化代码六

代码七

# -*- coding: utf-8 -*-
"""
    :author: zhangfq
    :order: 异步示例-通过回调函数实现
"""
import time
import threading


def longIO():
    print('开始执行耗时任务')
    time.sleep(5)
    print('结束耗时任务')
    yield 'zhang'


def genfunc(func):
    def wrapper(*args, **kwargs):
        gen1 = func(*args, **kwargs)
        gen2 = next(gen1)
        def run(g):
            res = next(g)
            try:
                gen1.send(res)
            except:
                pass
        threading.Thread(target=run, args=(gen2,)).start()
    return wrapper

@genfunc
def reqA():
    print('开始执行reqA')
    res = yield longIO()
    print('接收到的值:', res)
    print('结束执行reqA')

def reqB():
    print('开始执行reqB')
    time.sleep(2)
    print('结束执行reqB')

def main():
    reqA()
    reqB()

if __name__ == '__main__':
    main()



    开始执行reqA
    开始执行耗时任务
    开始执行reqB
    结束执行reqB
    结束耗时任务
    接收到的值: zhang
    结束执行reqA


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值