分布式异步消息框架构建笔记2——yield机制及单线程多任务系统
2014-12-08 12:57
393 查看
上一篇这边进行了一些结构上的设想,主要的核心内容就是消息和单线程实现.
这篇就介绍下如何通过C#中yield关键字,达到单线程执行多任务实现.
首先了解下yield的使用..
这段简单的代码,反编译看下..发现一条编译创建的类(<YieldTest>d_3)
找到原有类:
查看IL部分
从IL代码可以看出,其实yield其实是一个语法糖,
创建刚才多出来的那个类实例 然后返回.
看下MoveNext部分:
比较下我们原来的代码,
我们有2个也就是返回1,和返回2
每个状态在MoveNext中都对应1_state这个状态,
也就是,在底层实现中,每次都传入一个当前状态指针,然后执行对应的步骤.
这个也就是我们执行多任务的关键,虽然我们可以手写MoveNext结构,
但是这从调用和编写上都不友好,既然这里提供了语法糖那么我们善加利用就可以写出比较简单的代码了.
我们简单的从web上抓取2个网址这样一个例子来演示如何在一个线程中"同时"完成2个任务.
从输出结果上我们可以看出,2部分的代码虽然说不上同时运行,但是会被交替运行.
1执行一会 2执行一会,而且在同一个线程中,也就是达到我们多任务的要求..
进行下调用封装后,写起来和同步单线程没什么区别,而且,没有让人头疼的回调.
至于如何避免过程中那个While,在设计逻辑上其实也是可以避免的.
这篇就介绍下如何通过C#中yield关键字,达到单线程执行多任务实现.
首先了解下yield的使用..
public static IEnumerable<object> YieldTest() { int x = 0; x++; yield return x; x++; yield return x; }
这段简单的代码,反编译看下..发现一条编译创建的类(<YieldTest>d_3)
private sealed class <YieldTest>d__3 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable { // Fields private int <>1__state; private object <>2__current; private int <>l__initialThreadId; public int <x>5__4; // Methods [DebuggerHidden] public <YieldTest>d__3(int <>1__state) { this.<>1__state = <>1__state; this.<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } private bool MoveNext() { switch (this.<>1__state) { case 0: this.<>1__state = -1; this.<x>5__4 = 0; this.<x>5__4++; this.<>2__current = this.<x>5__4; this.<>1__state = 1; return true; case 1: this.<>1__state = -1; this.<x>5__4++; this.<>2__current = this.<x>5__4; this.<>1__state = 2; return true; case 2: this.<>1__state = -1; break; } return false; } [DebuggerHidden] IEnumerator<object> IEnumerable<object>.GetEnumerator() { if ((Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2)) { this.<>1__state = 0; return this; } return new Program.<YieldTest>d__3(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return this.System.Collections.Generic.IEnumerable<System.Object>.GetEnumerator(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } void IDisposable.Dispose() { } // Properties object IEnumerator<object>.Current { [DebuggerHidden] get { return this.<>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return this.<>2__current; } } }
找到原有类:
public static IEnumerable<object> YieldTest() { int iteratorVariable0 = 0; iteratorVariable0++; yield return iteratorVariable0; iteratorVariable0++; yield return iteratorVariable0; }
查看IL部分
.method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<object> YieldTest() cil managed { .maxstack 2 .locals init ( [0] class WindNet.Program/<YieldTest>d__3 d__, [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<object> enumerable) L_0000: ldc.i4.s -2 L_0002: newobj instance void WindNet.Program/<YieldTest>d__3::.ctor(int32) L_0007: stloc.0 L_0008: ldloc.0 L_0009: stloc.1 L_000a: br.s L_000c L_000c: ldloc.1 L_000d: ret }
从IL代码可以看出,其实yield其实是一个语法糖,
创建刚才多出来的那个类实例 然后返回.
看下MoveNext部分:
private bool MoveNext() { switch (this.<>1__state) { case 0: this.<>1__state = -1; this.<x>5__4 = 0; this.<x>5__4++; this.<>2__current = this.<x>5__4; this.<>1__state = 1; return true; case 1: this.<>1__state = -1; this.<x>5__4++; this.<>2__current = this.<x>5__4; this.<>1__state = 2; return true; case 2: this.<>1__state = -1; break; } return false; }
比较下我们原来的代码,
我们有2个也就是返回1,和返回2
每个状态在MoveNext中都对应1_state这个状态,
也就是,在底层实现中,每次都传入一个当前状态指针,然后执行对应的步骤.
这个也就是我们执行多任务的关键,虽然我们可以手写MoveNext结构,
但是这从调用和编写上都不友好,既然这里提供了语法糖那么我们善加利用就可以写出比较简单的代码了.
我们简单的从web上抓取2个网址这样一个例子来演示如何在一个线程中"同时"完成2个任务.
public static IEnumerable<string> Html1Get1() { WebClient wc = new WebClient(); bool done = false; string html = ""; int x = 0; wc.DownloadStringCompleted += (sender, e) => { done = true; html = e.Result; }; wc.DownloadStringAsync(new Uri("http://www.baidu.com")); while (!done) { x++; Console.WriteLine("Html1Get1:" + x); yield return null; } yield return html; } public static IEnumerable<string> Html1Get2() { WebClient wc = new WebClient(); bool done = false; string html = ""; int x = 0; wc.DownloadStringCompleted += (sender, e) => { done = true; html = e.Result; }; wc.DownloadStringAsync(new Uri("http://www.baidu.com")); while (!done) { x++; Console.WriteLine("Html1Get2:" + x); yield return null; } yield return html; } static void Main(string[] args) { var x1 = Html1Get1().GetEnumerator(); var x2 = Html1Get2().GetEnumerator(); while (x1.MoveNext() || x2.MoveNext()) { x1.MoveNext(); x2.MoveNext(); } Console.WriteLine(x1.Current.Substring(0,1000)); Console.WriteLine(x2.Current.Substring(0, 1000)); }
从输出结果上我们可以看出,2部分的代码虽然说不上同时运行,但是会被交替运行.
1执行一会 2执行一会,而且在同一个线程中,也就是达到我们多任务的要求..
进行下调用封装后,写起来和同步单线程没什么区别,而且,没有让人头疼的回调.
至于如何避免过程中那个While,在设计逻辑上其实也是可以避免的.
相关文章推荐
- 分布式异步消息框架构建笔记4——分布式消息路由
- 分布式异步消息框架构建笔记5——如何避开并行编程中的数据共享陷阱
- 分布式异步消息框架构建笔记3 —— 自动消息路由
- 分布式异步消息框架构建笔记 1—— 设想
- Android(java)学习笔记149:AsyncTask(异步任务)和Handler(消息机制)
- Android系统中异步消息处理线程机制的理解
- Android中AsyncTask(异步任务)和Handler(线程消息机制)的详解
- Android多线程及异步任务消息处理机制(一)--Handler的使用
- 安卓异步线程消息机制学习——Handler+Thread+Looper
- 基于JMS消息中间件的分布式系统初探究(一) - 通过JMS实现Web服务器与服务框架的通讯
- 面对软件错误构建可靠的分布式系统_笔记05
- AsyncTask异步任务线程框架(二)
- 面对软件错误构建可靠的分布式系统_笔记08
- 面对软件错误构建可靠的分布式系统_笔记06
- Android线程之异步消息处理机制(一)
- 面对软件错误构建可靠的分布式系统_笔记12
- 面对软件错误构建可靠的分布式系统_笔记09
- 面对软件错误构建可靠的分布式系统_笔记04
- android 进程/线程管理(一)----消息机制的框架
- Android线程之异步消息处理机制(二)——Message、Handler、MessageQueue和Looper