协程是个啥玩意

Python协程详解

Python中有一个协程的概念,那么,协程是个啥玩意呢?

协程,又称微线程,纤程。英文名Coroutine。

协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。

通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。

协程和线程的差异

在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。

实现1(yield)

import time

def a():
    while True:
        print('---1---')
        yield None
        time.sleep(0.5)

def b():
    while True:
        print('---2---')
        yield None
        time.sleep(0.5)

if __name__ == '__main__':
    t1 = a()
    t2 = b()
    while True:
        next(t1)
        next(t2)

运行结果:

循环打印

实现2(greenlet)

from greenlet import greenlet
import time

def a():
    while True:
        print('---1---')
        gr2.switch()
        time.sleep(0.5)

def b():
    while True:
        print('---2---')
        gr1.switch()
        time.sleep(0.5)

if __name__ == '__main__':
    gr1 = greenlet(a)
    gr2 = greenlet(b)

    # 切换到gr1执行
    gr1.switch()

运行结果同上。

实现3(gevent)

greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块,就是gevent。

其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

import gevent
from gevent import monkey
import time

#打补丁
#如果不打补丁的话,下面就必须写上gevent.sleep(0.5)
monkey.patch_all()

def a():
    while True:
        print('---1---')
        time.sleep(0.5)

def b():
    while True:
        print('---2---')
        time.sleep(0.5)

if __name__ == '__main__':
    g1 = gevent.spawn(a)
    g2 = gevent.spawn(b)

    g1.join()
    g2.join()

运行结果同上。

gevent强大在当有耗时操作的时候,会自动切换其他不耗时的协程。

import gevent
from gevent import monkey
import time

#打补丁
#如果不打补丁的话,下面就必须写上gevent.sleep(0.5)
monkey.patch_all()

def f(n):
    for i in range(n):
        print(gevent.getcurrent(), i)
        #用来模拟一个耗时操作
        time.sleep(1)

gevent.joinall([
    gevent.spawn(f, 5),
    gevent.spawn(f, 5),
    gevent.spawn(f, 5)
])

运行结果:

如果我们不加打补丁,即红色部分,则不会自动切换,运行结果如下:

最后附上一个多协程并发下载示例:

from gevent import monkey
import gevent
import urllib.request

#有IO才做时需要这一句
monkey.patch_all()

def my_downLoad(file_name, url):
    print('GET: %s' % url)
    resp = urllib.request.urlopen(url)
    data = resp.read()

    with open(file_name, "wb") as f:
        f.write(data)

    print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([
        gevent.spawn(my_downLoad, "1.mp4", 'http://....mp4'),
        gevent.spawn(my_downLoad, "2.mp4", 'http://....mp4'),
])

 

转载于:https://www.cnblogs.com/DarrenChan/p/10349142.html

<think>好的,我需要给用户解释Unity协程中的挂起是什么意思。首先,我得回想一下自己学过的协程相关知识。协程在Unity中是用来处理需要分步执行的任务的,比如等待一段时间或者加载资源。 用户问的是“挂起”这个术语,所以我要先明确挂起在协程中的具体含义。记得协程是通过IEnumerator实现的,里面用yield return来暂停执行。这时候协程会被挂起,也就是暂停,直到满足某个条件再继续。 接下来,我需要解释挂起时发生了什么。Unity的主线程是单线程的,协程的挂起并不会阻塞整个线程,而是将控制权交还给引擎,这样其他游戏逻辑还能继续运行。这点很重要,避免用户误以为挂起会导致游戏卡顿。 然后要举例说明常见的挂起情况。比如yield return new WaitForSeconds(1f),等待1秒后继续。还有等待异步操作完成,像WWW或者UnityWebRequest的发送请求。还有等待其他协程结束的情况,比如yield return StartCoroutine()。 可能用户不太明白挂起和普通函数返回的区别,这里需要强调协程可以多次暂停和恢复,而普通函数执行完就结束了。这点是协程的优势,适合处理需要分步的任务。 另外,要提醒用户虽然协程挂起不会阻塞主线程,但如果在协程中执行大量计算还是会卡顿,可能需要分帧处理。这也是优化时需要注意的地方。 最后,整理这些点,用简单易懂的语言组织起来,避免使用太专业的术语,让用户能够明白挂起的机制和使用场景。检查有没有错误,比如是否正确区分了线程和协程的执行方式,确保举例正确,语法正确,结构清晰。</think>Unity协程中的"挂起"是协程执行过程中**暂停当前代码执行,但保持上下文状态**的特殊行为。这是通过`yield return`语句实现的,核心机制如下: --- ### 举个实际开发案例 ```csharp IEnumerator ShootLaser() { // 阶段1:蓄力 laser.PlayChargeEffect(); yield return new WaitForSeconds(1.5f); // 挂起1.5秒 // 阶段2:发射 laser.Fire(); yield return null; // 挂起至下一帧 // 阶段3:后坐力 camera.Shake(0.3f); yield return new WaitForFixedUpdate(); // 挂起到物理帧 // 阶段4:冷却 while(cooldownTimer > 0){ cooldownTimer -= Time.deltaTime; yield return null; // 每帧挂起 } } ``` --- ### 挂起原理图解 ``` 协程开始 ↓ 执行代码块A ↓ yield return条件 → [挂起点] → 满足条件时唤醒 ↓ 执行代码块B ↓ yield return条件 → [挂起点] → 满足条件时唤醒 ↓ ...... ``` --- ### 关键特性 1. **非阻塞性挂起** - 协程挂起时主线程继续执行其他逻辑 - 不同于线程阻塞(不会导致游戏卡死) 2. **状态保持** - 局部变量值会被保留 - 执行位置会被记忆 3. **唤醒条件** - `WaitForSeconds`:时间到达 - `WaitForFixedUpdate`:物理帧更新 - `WWW/AsyncOperation`:异步操作完成 - `Coroutine`:等待其他协程结束 --- ### 典型使用场景 1. **分帧加载**:将耗时操作分散到多帧 2. **动画序列**:编排复杂的时间事件链 3. **AI行为树**:实现状态切换等待 4. **网络请求**:等待服务器响应期间不阻塞游戏 --- ### 注意事项 ⚠️ 协程不是线程,所有逻辑仍在主线程执行 ⚠️ 避免在协程内进行复杂计算(应分到多帧) ⚠️ GameObject被销毁时协程会自动终止 ⚠️ 可通过`StopCoroutine()`主动终止协程 理解协程的挂起机制,可以更好地实现游戏中的时序控制和异步逻辑处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值