分布式异步消息框架构件2——yield机制及单线程多任务系统

上一篇这边进行了一些结构上的设想,主要的核心内容就是消息和单线程实现.

这篇就介绍下如何通过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,在设计逻辑上其实也是可以避免的.

时间: 2024-11-08 03:39:36

分布式异步消息框架构件2——yield机制及单线程多任务系统的相关文章

分布式异步消息框架构件3 —— 自动消息路由

这个系列慢慢变成先设想后完成的模式了,上篇我们测试了以Yield当多任务处理. 楼主写了个小Demo也完成了类似功能,并且支持中途等待,直接等到完成回调后,继续处理下一阶段. 这个功能可以完成类似逻辑事件流,比如C需要等待A,B完成后再执行,而且写法也比较简单.直接上代码: //创建事件,把Handle丢入Yield队列, //执行当发现有等待Handle状态为YieldWating //放入YieldWating队列 //回调时检查YieldWating队列,重新激活 Context.Wati

分布式异步消息框架构件 —— 设想

前几天在查看关于 Actor模式的一些资料,包括Erlang在游戏中一些资料,虽然本人不会Erlang但是稍微看了下编写方式.觉得还是有可借鉴的地方的.因为实在不熟悉不枉加评论了.这里说下自己的一些理解. 从这几年Erlang和函数式编程的崛起,引发OOP编程的一些不足,但是OOP并不妨碍获得相关的优点,只不过需要一些有效的框架和规范支持. 首先这里有几个简单的问题: 1.OOP方式面临多线程,跨进程访问问题,那么就有所谓的锁问题. 2.函数式编程的优点,不可变数据,并发时无需关心对象状态是否会

分布式异步消息框架构建笔记5——如何避开并行编程中的数据共享陷阱

任何多线程/并行/分布式都会面临一个问题,"数据状态共享". 有经验的开发者会说,要想正确有效的避开避开状态共享,那么就应该别用任何状态共享. 虽然不得不说,这是一个不错的建议,但是没有状态共享,你需要如何才能知道非本地数据的状态? 也许你会说使用消息,使用消息来处理,那么我们丑陋的回调金字塔应该叠的更高了. 不得不说这是一个解决办法,但是为了保持状态不被修改,那么我们还得在远程申请一个写入锁,防止数据被别的任务所修改. 那么流程就是 申请锁->请求某个消息状态->释放锁

分布式异步消息框架构建笔记4——分布是消息路由

上一篇实现了消息的自动路由,这边写了一个小测试,大家可以猜一下运行输出结果是什么? public class RouterTest { public static void DoRouterTest() { var contextA = Context.Creat("A"); var contextB = Context.Creat("B"); contextA.RegServiceClass(typeof (MyClassA)); contextB.RegServ

Python开发【模块】:Celery 分布式异步消息任务队列

Celery 前言: Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, 举几个实例场景中可用的例子: 你想对100台机器执行一条批量命令,可能会花很长时间 ,但你不想让你的程序等着结果返回,而是给你返回 一个任务ID,你过一段时间只需要拿着这个任务id就可以拿到任务执行结果, 在任务执行ing进行时,你可以继续做其它的事情. 你想做一个定时任务,比如每天检测一下你们所有客户的

异步消息的传递-回调机制

简介: 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用.回调和异步调用.同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用:回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口:异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口).回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知.同步

基于Scala的Actor之上的分布式并发消息驱动框架Akka初体验

学习了基于Scala的Actor之上的分布式并发消息驱动框架Akka初体验,应用actor模型,位置透明,做到高并发.可伸缩.容错.单机也可以用,水平扩展.垂直扩展.容错都有很好的表现,spark中的例子如下: private def initializeEventProcessActor(){ implicat val timeout=Timeout( 30 seconds) val initEventActorReply= dagSchedulerActorSupervisor ? Prop

拨云见日---android异步消息机制源码分析

做过windows GUI的同学应该清楚,一般的GUI操作都是基于消息机制的,应用程序维护一个消息队列,开发人员编写对应事件的回调函数就能实现我们想要的操作 其实android系统也和windows GUI一样,也是基于消息机制,今天让我们通过源码来揭开android消息机制的神秘面纱 谈起异步消息,就不能不提及Handler,在安卓中,由于主线程中不能做耗时操作,所以耗时操作必须让子线程执行,而且只能在主线程(即UI线程)中执行UI更新操作,通过Handler发送异步消息,我们就能更新UI,一

Handler详解系列(一)——Handler异步消息机制详解(附图)

MainActivity如下: package cc.cn; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.app.Activity; /** * Demo描述: * Android异步消息机制分析(附图) * * ===================