六狼论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博账号登陆

只需一步,快速开始

搜索
查看: 57|回复: 0

使用C#的Generator编写并发程序

[复制链接]

升级  98%

158

主题

158

主题

158

主题

举人

Rank: 3Rank: 3

积分
494
 楼主| 发表于 2013-1-27 05:27:35 | 显示全部楼层 |阅读模式
前面说地Generator编写并发程序的优势,当然它本身没有这种能力,需要为它编写调度程序。

今天抽点时间写了个简单的,还是满好玩的,它可以调度多个“友好”的并发任务,包括:
1、用户自己编写的适时交出控制权的过程
2、网络IO

由于对C#不是很熟,所以写的可能比较难看,而且IO也只支持网络,有兴趣的可以研究改进一下,比如把它改成SMP版本,增加Actor模型,处理更多的IO模式等。

实现方式基本上是从IoLanguage里面抄过来的,我已经用它编写过Ruby/C++/D/C#版本,当然目前仅限于测试它的切换性能。

好消息是如果你实现得比较好,C#版本性能完全可以超过Erlang,Ruby的Fiber就比较差一些,C++/D里面使用Fiber/ucontext性能也不是很好,Generator性能是最好的。

由于时间短,只测试了ReadEvent,WriteEvent没有测试,这个也是有多种实现方式可以研究的。这里实现的调度器性能不是很好,可能是List用法性能太差,没有仔细测试。
using System;using System.Threading;using System.Collections;using System.Collections.Generic;using System.Net.Sockets;using System.Net;namespace ConsoleApplication1{    public enum EventType    {        ReadEvent = 1,        WriteEvent = 2    }    public class Event    {        private Socket sock;        private EventType eventType;        private IEnumerator<int> task;        public Event(Socket sock, EventType eventType)        {            this.sock = sock;            this.eventType = eventType;        }        public Socket getSocket()        {            return sock;        }        public EventType getEventType()        {            return eventType;        }        public void setTask(IEnumerator<int> task)        {            this.task = task;        }        public IEnumerator<int> getTask()        {            return task;        }        public void onEvent()        {            Console.WriteLine("onEvent");            Scheduler.scheduleNow(task);        }    }    public class ReadEvent : Event    {        public ReadEvent(Socket sock)            :base(sock, EventType.ReadEvent)        {                    }    }    public class WriteEvent : Event    {        public WriteEvent(Socket sock)            : base(sock, EventType.WriteEvent)        {        }    }    class EventManager    {        private IDictionary<Socket, Event> readEvents = new Dictionary<Socket, Event>();        private IDictionary<Socket, Event> writeEvents = new Dictionary<Socket, Event>();        private IEnumerator<int> myTask = null;        public int registerHandler(Event ev)        {            Console.WriteLine("registerHandler");            if ((ev.getEventType() & EventType.ReadEvent) > 0)            {                readEvents.Add(ev.getSocket(), ev);            }            else            {                writeEvents.Add(ev.getSocket(), ev);            }            if (myTask == null)                myTask = runLoop();            Scheduler.scheduleNow(myTask);            return 0;        }        public IEnumerator<int> runLoop()        {            Console.WriteLine("enter run");            do            {                Console.WriteLine("run loop");                yield return 1;                IList rlist = new List<Socket>(readEvents.Keys);                IList wlist = new List<Socket>(writeEvents.Keys);                int timeoutMS = 1000000;                if (Scheduler.hasEvents()) timeoutMS = 0;                //Console.WriteLine("begin select: " + rlist.Count + ", " + wlist.Count);                Socket.Select(rlist, wlist, null, timeoutMS);                //Console.WriteLine("end select: " + rlist.Count + ", " + wlist.Count);                Socket sock = null;                Event ev = null;                if (rlist.Count > 0)                {                    sock = (Socket)rlist[0];                    readEvents.TryGetValue(sock, out ev);                    readEvents.Remove(sock);                }                else if (wlist.Count > 0)                {                    sock = (Socket)wlist[0];                    writeEvents.TryGetValue(sock, out ev);                    writeEvents.Remove(sock);                }                if (ev != null)                    ev.onEvent();            } while (readEvents.Count != 0 || writeEvents.Count != 0);            myTask = null;        }    }    public static class Scheduler    {        public delegate IEnumerable<int> T();        [ThreadStatic]        private static IList<IEnumerator<int>> tasks = new List<IEnumerator<int>>();        [ThreadStatic]        private static EventManager eventManager = new EventManager();        [ThreadStatic]        private static Event lastEvent;        public static bool hasEvents()        {            return tasks.Count > 0;        }        public static void spawn(T del)        {            var task = del().GetEnumerator();            schedule(task);        }        public static void schedule(IEnumerator<int> task)        {            tasks.Remove(task);            if (lastEvent != null)                lastEvent.setTask(task);            else                tasks.Add(task);            lastEvent = null;        }        public static void scheduleNow(IEnumerator<int> task)        {            tasks.Remove(task);            tasks.Insert(0, task);        }        public static void remove(IEnumerator<int> task)        {            Console.WriteLine("remove task");            tasks.Remove(task);        }        public static void run()        {            while (tasks.Count > 0)            {                IEnumerator<int> task = tasks[0];                tasks.RemoveAt(0);                bool ret = task.MoveNext();                if (ret)                    schedule(task);            }        }        public static int registerAndWaitEvent(Event ev)        {            lastEvent = ev;            return eventManager.registerHandler(ev);        }    }    // 测试程序:    class Program    {        public static IEnumerable<int> test(string id)        {            for (int i = 0; i < 5; i++)            {                System.Console.WriteLine("id: " + id + ", " +i);                yield return i;            }        }        public static IEnumerable<int> clientLoop(Socket client)        {            while (true)            {                Console.WriteLine("client loop");                yield return Scheduler.registerAndWaitEvent(new ReadEvent(client));                byte[] buffer = new byte[1024];                int ret = client.Receive(buffer);                if (ret > 0)                {                    //Console.WriteLine(buffer);                    client.Send(buffer);                }                else                {                    client.Close();                    break;                }            }        }        public static IEnumerable<int> serverLoop()        {            Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);            IPHostEntry IPHost = Dns.GetHostEntry("localhost");             sock.Bind(new IPEndPoint(IPHost.AddressList[0], 23456));            sock.Listen(128);            while(true) {                Console.WriteLine("server loop");                yield return Scheduler.registerAndWaitEvent(new ReadEvent(sock));                Console.WriteLine("accept event");                Socket client = sock.Accept();                Scheduler.spawn(() => clientLoop(client));            }        }        static void Main(string[] args)        {            Scheduler.spawn(() => test("a"));            Scheduler.spawn(() => test("b"));            Scheduler.spawn(() => serverLoop());            Scheduler.run();        }    }}
您需要登录后才可以回帖 登录 | 立即注册 新浪微博账号登陆

本版积分规则

快速回复 返回顶部 返回列表