python 协程和进程的区别

协程和线程都可用于实现并行操作,但协程是在操作的空余时间处理其他异步任务,线程是多个任务同时运行,以下代码用于体现两者的区别:

import time, threading, asyncio

c=[1,2,3,4,5]

async def async_function():
    # 异步操作
    _s = random.random()/100
    c.append(_s)
    time.sleep(_s)
    _a = c.pop()
    print(_a, _s, _a == _s)

async def main():
    await asyncio.gather(*[asyncio.create_task(async_function()) for i in range(100)])


# 协程运行
asyncio.run(main())

import time, threading

def thread_function():
    # 线程操作
    _s = random.random()/100
    c.append(_s)
    time.sleep(_s)
    _a = c.pop()
    print(_a, _s, _a == _s)


# 线程运行
_t = [threading.Thread(target=thread_function) for i in range(100)]
[i.start() for i in _t]

上述代码示例是对数组资源存取的场景,可见协程和线程最大的区别在于,协程在未使用await挂起等待时,其运行状态是串行的,即当多个协程函数等待执行时,其运行逻辑为逐步执行函数,直至使用asyncio.sleep函数挂起为止,若所有协程函数中都不存在挂起,则其相当于串行运行。

因此,使用协程可以避免在并发时的资源竞争问题,在线程中,多个函数可能交错运行,即函数A存入数据后,下一个时钟,执行的是函数B中取数据语句,就导致A存入数据被B取走,使得A在取数据时无法取得原数据;

而在协程中,执行函数A时,直至使用asyncio.sleep函数挂起前,都不会执行其他函数语句,即使它们是并发关系。
以下是使用asyncio.sleep函数挂起时场景:

import time, threading, asyncio

c=[1,2,3,4,5]

async def async_function():
    # 异步操作
    _s = random.random()/100
    c.append(_s)
    await asyncio.sleep(_s)
    _a = c.pop()
    print(_a, _s, _a == _s)

async def main():
    await asyncio.gather(*[asyncio.create_task(async_function()) for i in range(100)])
    
# 运行结果:
0.0050215246774124 0.008355202463023723 False
0.001243457129550033 0.008433923407809477 False
0.007144714089392097 0.008856375597333826 False
0.0017091160109593251 0.008943085497665414 False
0.006342389888474282 0.009343197737486436 False
0.004420504786995938 0.009430787253709298 False
0.007630802209911164 0.009434310107449101 False
0.006821582117520494 0.009805267620512585 False
0.00022131310225208533 0.009826294183283412 False
0.0035083056383737278 0.009864054240290415 False

可见此时现象与使用线程时一致,因为协程函数在存入数据后,使用asyncio.sleep挂起,使得其他并行协程可以取走数据,导致资源竞争;

为避免上述问题,则应避免存在竞争的资源在结束占用前使协程挂起,如下所示:

import time, threading, asyncio

c=[1,2,3,4,5]

async def async_function():
    # 异步操作
    _s = random.random()/100
    c.append(_s)
    _a = c.pop()
    await asyncio.sleep(_s)
    print(_a, _s, _a == _s)

async def main():
    await asyncio.gather(*[asyncio.create_task(async_function()) for i in range(100)])
    
# 运行结果:
0.007676443440870865 0.007676443440870865 True
0.007919321779395496 0.007919321779395496 True
0.007933492729721329 0.007933492729721329 True
0.008050559502540175 0.008050559502540175 True
0.008229436038698515 0.008229436038698515 True
0.008455254940554775 0.008455254940554775 True
0.008524029430646137 0.008524029430646137 True
0.008594481682382494 0.008594481682382494 True
0.008742299722736128 0.008742299722736128 True
0.008810518281412187 0.008810518281412187 True
0.008880150259979994 0.008880150259979994 True

可见此时不再发生资源竞争。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值