本文主要介绍异步和同步的区别以及实现方式,如何用python实现。 干货满满,相信看完不会失望!!!
同步是阻塞模式,异步是非阻塞模式。
如上图,当用户创建一笔电商交易订单时,要经历的业务逻辑流程还是很长的,每一步都要耗费一定的时间,那么整体的RT就会比较长。 于是,人们开始思考能不能将一些非核心业务从主流程中剥离出来,于是有了异步编程雏形,如下图。
异步编程是让程序并发运行的一种手段。它允许多个事件同时发生,当程序调用需要长时间运行的方法时,它不会阻塞当前的执行流程,程序可以继续运行。 ⚡ 核心思路: 采用多线程优化性能,将串行操作变成并行操作。异步模式设计的程序可以显著减少线程等待,从而在高吞吐量场景中,极大提升系统的整体性能,显著降低时延。
threading.Threadyieldasyncio
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import thread
import time
# 为线程定义一个函数
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print "%s: %s" %
( threadName, time.ctime(time.time()) )
# 创建两个线程
try:
thread.start_new_thread(
print_time, ("Thread-1", 2, ) )
thread.start_new_thread(
print_time, ("Thread-2", 4, ) )
except:
print "Error: unable to start thread"
while 1:
pass
输出如下
Thread-1: Thu Jan 22 15:42:17 2009
Thread-1: Thu Jan 22 15:42:19 2009
Thread-2: Thu Jan 22 15:42:19 2009
Thread-1: Thu Jan 22 15:42:21 2009
Thread-2: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:25 2009
Thread-2: Thu Jan 22 15:42:27 2009
Thread-2: Thu Jan 22 15:42:31 2009
Thread-2: Thu Jan 22 15:42:35 2009
线程是cpu调度的最小单位,多线程运行的本质是对cpu资源的竞争,调用本质是系统级别的上下文切换, 一般用于io密集型应用,否则竞争不到线程锁,多线程也会变得毫无意义。
实例代码如下
def for_test():
for i in range(3):
yield i
def yield_yield_test():
yield from range(3)
输出如下
[0, 1, 2]
[0, 1, 2]
tips:
利用多核CPU最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率, 可获得极高的性能。
@asyncio.coroutine --> async def
yield from --> await
最简单的实例代码如下
import asyncio
async def coroutine_example():
await asyncio.sleep(1)
print ('Fosen')
if __name__ == "__main__":
coro = coroutine_example()
loop = asyncio.get_event_loop()
loop.run_until_complete(coro)
loop.close()
输出如下
暂停一秒后,打印“Fosen”
tips:
若在协程中需要有延时操作,应该使用 await asyncio.sleep(),而不是使用time.sleep()。 因为使用time.sleep()后会释放GIL,阻塞整个主线程,从而阻塞整个事件循环。
实例代码如下
import asyncio
from threading import Thread
def start_thread_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
def thread_example(name):
print ('正在执行:', name)
return '返回结果:' + name
if __name__ == "__main__":
new_loop = asyncio.new_event_loop()
t = Thread(target=start_thread_loop,
args=(new_loop,))
t.start()
handle = new_loop.call_soon_threadsafe(
thread_example, '1')
handle.cancel()
new_loop.call_soon_threadsafe(
thread_example, '2')
print ('主线程不阻塞')
new_loop.call_soon_threadsafe(
thread_example, '3')
print ('继续运行中...')
输出如下
正在执行: 2
主线程不阻塞
继续运行中...
正在执行: 3
tips:
同步的好处是,当运行的程序有先后顺序关系,则避免了一些并发会带来的问题。
实例代码如下
import asyncio
from threading import Thread
def start_thread_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
async def thread_example(name):
print ('正在执行:', name)
await asyncio.sleep(1)
return '返回结果:' + name
if __name__ == "__main__":
new_loop = asyncio.new_event_loop()
t = Thread(target=start_thread_loop,
args=(new_loop,))
t.setDaemon(True)
t.start()
future = asyncio.run_coroutine_threadsafe(
thread_example('1'), new_loop)
print (future.result())
asyncio.run_coroutine_threadsafe(
thread_example('2'), new_loop)
print ('主线程不阻塞')
asyncio.run_coroutine_threadsafe(
thread_example('3'), new_loop)
print ('继续运行中...')
输出如下
正在执行: 1
返回结果:1
主线程不阻塞
正在执行: 2
继续运行中...
正在执行: 3
实例代码如下
import asyncio
from threading import Thread
from collections import deque
import random
import time
def start_thread_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
def consumer():
while True:
if dp:
msg = dp.pop()
if msg:
asyncio.run_coroutine_threadsafe(
thread_example('Fosen_{}'.format(msg)), new_loop)
async def thread_example(name):
print ('正在执行:', name)
await asyncio.sleep(2)
return '返回结果:' + name
if __name__ == "__main__":
dp = deque()
new_loop = asyncio.new_event_loop()
loop_thread = Thread(target=start_thread_loop,
args=(new_loop,))
loop_thread.setDaemon(True)
loop_thread.start()
consumer_thread = Thread(target=consumer)
consumer_thread.setDaemon(True)
consumer_thread.start()
while True:
i = random.randint(1, 10)
dp.appendleft(str(i))
time.sleep(2)
输出如下
正在执行: Fosen_6
正在执行: Fosen_2
正在执行: Fosen_8
正在执行: Fosen_2
正在执行: Fosen_1
正在执行: Fosen_3
正在执行: Fosen_1
实例代码如下
import asyncio
from threading import Thread
import redis
# 生产者代码
def producer():
for i in range(4):
redis_conn.lpush('Fosen', str(i))
# 消费者代码
def get_redis():
conn_pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
return redis.Redis(connection_pool=conn_pool)
def start_thread_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
async def thread_example(name):
print ('正在执行:', name)
await asyncio.sleep(2)
return '返回结果:' + name
if __name__ == "__main__":
redis_conn = get_redis()
producer()
new_loop = asyncio.new_event_loop()
loop_thread = Thread(target=start_thread_loop,
args=(new_loop,))
loop_thread.setDaemon(True)
loop_thread.start()
while True:
msg = redis_conn.rpop('Fosen')
if msg:
asyncio.run_coroutine_threadsafe(
thread_example('Fosen_{}'.format(msg)), new_loop)
输出如下
正在执行: Fosen_b'0'
正在执行: Fosen_b'1'
正在执行: Fosen_b'2'
正在执行: Fosen_b'3'
asyncio的用法