Coroutine的原理以及实现
最近在写WinForm,在UI界面需要用到异步的操作,比如加载数据的同时刷系进度条,WinForm提供了不少多线程的操作,
但是多线程里,无法直接修改主线程里添加的UI的get/set属性访问器(可以通过关闭线程安全警告来暴力操作,但是不推荐),
另外的方法就是利用BackgroundWorker来实现线程间通信,主线程实现UI的刷系操作,其他线程通过向主线程发送ProgressChanged来通知主线程刷新UI。
实在是不太想使用多线程,于是想到了Unity的协程,单线程实现的异步操作,简单的反编译了Coroutine的源码跟上网搜了下资料,大概的弄懂了下它的原理:
参考文章:
https://blog.csdn.net/zhou8jie/article/details/49024791
https://blog.csdn.net/qq_30695651/article/details/79105332
1.Coroutine最关键的一个地方,利用到了IEnumerator接口,它是一个迭代器,你可以把它当成指向一个序列的某个节点的指针,它提供了两个重要的接口,分别是Current(返回当前指向的元素)和MoveNext()(将指针向前移动一个单位,如果移动成功,则返回true,如果已经移动到末尾,则返回false)
关于IEnumerator参考:
C#--IEnumerable 与 IEnumerator 的区别
2.yield,yield return 返回,可以返回null,true/false,或者一个IEnumerator
3.所以协程的内部,你可以想象成一条Action执行序列,例如:
Action1 -> Action2 -> ...
在执行完Action1的时候,返回true,该协程被挂起,并记录当前位置,下一帧,继续从上次的位置往下执行,直到执行完所有操作,返回false,此时执行完毕。
思想有点像行为树,同样是执行到Action,通过返回值决定是不是要挂起,只不过行为树没帧都是从头遍历,而协程只会从最后的位置继续执行。
4.因此不要以为协程能实现异步就跟多线程一样,他只是跟多线程一样可以并行执行,原理就是把步骤分割然后每帧调用其中的一些,实际上还是单线程的,如果某个动作占用太多的运算,
还是会给主线程造成严重影响的。
自己手动实现一个协程:
using System.Collections;
using System.Collections.Generic; namespace Com.Coroutine
{ public class Coroutine
{ internal IEnumerator m_Routine; internal IEnumerator Routine
{
get { return m_Routine; }
} internal Coroutine()
{
} internal Coroutine(IEnumerator routine)
{
this.m_Routine = routine;
} internal bool MoveNext()
{ var routine = m_Routine.Current as Coroutine; if (routine != null)
{
if (routine.MoveNext())
{
return true;
}
else if (m_Routine.MoveNext())
{
return true;
}
else
{
return false;
}
}
else if (m_Routine.MoveNext())
{
return true;
}
else
{
return false;
}
}
} // use this as a template for functions like WaitForSeconds()
public class WaitForCount : Coroutine
{
int count = ;
public WaitForCount(int count)
{
this.count = count;
this.m_Routine = Count();
} IEnumerator Count()
{
while (--count >= )
{
System.Console.WriteLine(count);
yield return true;
}
}
} // use this as the base class for enabled coroutines
public class CoroutineManager
{ internal List<Coroutine> m_Coroutines = new List<Coroutine>(); // just like Unity's MonoBehaviour.StartCoroutine
public Coroutine StartCoroutine(IEnumerator routine)
{
var coroutine = new Coroutine(routine);
m_Coroutines.Add(coroutine);
return coroutine;
} // call this every frame
public void ProcessCoroutines()
{
for (int i = ; i < m_Coroutines.Count; )
{
var coroutine = m_Coroutines[i];
if (coroutine.MoveNext())
{
++i;
}
else if (m_Coroutines.Count > )
{
m_Coroutines[i] = m_Coroutines[m_Coroutines.Count - ];
m_Coroutines.RemoveAt(m_Coroutines.Count - );
}
else
{
m_Coroutines.Clear();
break;
}
}
}
}
}
Coroutine的原理以及实现的更多相关文章
- Unity协程(Coroutine)原理深入剖析
Unity协程(Coroutine)原理深入剖析 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 其实协程并没有那么复杂,网上很多地方都说是多 ...
- Unity协程(Coroutine)原理深入剖析再续
Unity协程(Coroutine)原理深入剖析再续 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 前面已经介绍过对协程(Coroutine ...
- 【转】Unity协程(Coroutine)原理深入剖析
Unity协程(Coroutine)原理深入剖析 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 记得去年6月份刚开始实习的时候,当时要我写网 ...
- Unity协程(Coroutine)原理深入剖析(转载)
记得去年6月份刚开始实习的时候,当时要我写网络层的结构,用到了协程,当时有点懵,完全不知道Unity协程的执行机制是怎么样的,只是知道函数的返回值是IEnumerator类型,函数中使用yield r ...
- c coroutine
今天看了下云风c coroutine 代码 博客,发现 coroutine 实现原理其实还比较简单,就用户态栈切换,只需要几十行汇编,特别轻量级. 具体实现 1. 创建一个coroutine: 也就 ...
- libcoro:在c++中支持coroutine
起因 在第一个版本的libtnet开发完成之后,我一直在思考如何让异步方式的网络编程更加简单. 虽然libtnet通过c++ shared_ptr以及function等技术很大程度上面解决了异步代码编 ...
- unity协程coroutine浅析
转载请标明出处:http://www.cnblogs.com/zblade/ 一.序言 在unity的游戏开发中,对于异步操作,有一个避免不了的操作: 协程,以前一直理解的懵懵懂懂,最近认真充电了一下 ...
- yield学习续:yield return迭代块在Unity3D中的应用——协程
必读好文推荐: Unity协程(Coroutine)原理深入剖析 Unity协程(Coroutine)原理深入剖析再续 上面的文章说得太透彻,所以这里就记一下自己的学习笔记了. 首先要说明的是,协程并 ...
- tornado 异步
引言 注:正文中引用的 Tornado 代码除特别说明外,都默认引用自 Tornado 4.0.1. tornado.gen 模块是一个基于 python generator 实现的异步编程接口.通过 ...
随机推荐
- 英语词性系列-B02-动词
诗Poem 要求:背诵这首诗,翻译现代文,根据现代文用简单的英文翻译. 动词直观体会 动词 动词 动词 动词 动词 sell卖 buy买 beat击打 look看 dance跳舞 sing唱歌 spe ...
- 面向对象_内置函数 property
property 将方法伪装成为属性,可以不用加上()就可以调出其属性. 但是用__dict__,不能调出此属性 from math import pi class Circle: def __ini ...
- 好程序员分享居中一个float元素
好程序员分享居中一个float元素,我们布局的时候,用margin来设置float元素的外边距来达到效果.对于,在文档流中的元素,我们很容易让它水平居中,只要给元素设置一个固定的宽度,用margin: ...
- Python两大佬互相撕逼 技术何苦为难技术?
最近两天 Python 圈发生了一件大事,两个 Python 大佬撕逼了起来了. 不,其实是一个大佬(刘志军)被怼. 事情是这样的. 背景 人物介绍: 董明伟:公众号「Python 之美」的作者,似乎 ...
- spring+struts2+hibernate框架搭建(Maven工程)
搭建Spring 1.porm.xml中添加jar包 <!-- spring3 --> <dependency> <groupId>org.springframew ...
- Python——模块——随机模块
1.引用模块 import random 2.随机整数 random.randint(a,b) 3.随机浮点数 random.uniform(a,b) 4.从列表中随机取元素 random.choic ...
- Netty 5 io.netty.util.IllegalReferenceCountException 异常
异常信息 io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1 原因 handler 继承了 SimpleChan ...
- 使用mongo-express管理mongodb数据库
前面的话 本文将详细介绍一款用nodejs开发的基于Web的mongodb数据库管理工具mongo-express 安装 首先,全局安装 mongo-express 包 npm install -g ...
- LOJ2340 [WC2018] 州区划分 【FMT】【欧拉回路】
题目分析: 这题是WC的题??? 令 $g[S] = (\sum_{x \in S}w_x)^p$ $h[S] = g[S]$如果$S$不是欧拉回路 $d[S] = \frac{f[S]}{g[All ...
- 【AGC015E】Mr.Aoki Incubator DP
题目描述 数轴上有\(n\)个人,每个人的位置是\(x_i\),速度是\(v_i\). 最开始有一些人感染了传染病. 如果某一时刻一个正常人和一个被感染的人处于同一位置,那么这个正常人也会被感染. 问 ...