C# 使用CCR顺序处理事件的有效方法是什么?

C# 使用CCR顺序处理事件的有效方法是什么?,c#,iterator,ccr,C#,Iterator,Ccr,我曾尝试使用CCR迭代器来解决一项任务,该任务需要并行处理成吨的数据源,其中来自每个源的数据需要按顺序处理。没有一个提要相互依赖,因此每个提要的顺序处理可以并行 下面是一个带有一个整数馈送的快速脏模型,它只是以大约1.5K/秒的速率将整数推入端口,然后使用CCR迭代器将其取出,以保持有序处理保证 class Program { static Dispatcher dispatcher = new Dispatcher(); static DispatcherQueue dispa

我曾尝试使用CCR迭代器来解决一项任务,该任务需要并行处理成吨的数据源,其中来自每个源的数据需要按顺序处理。没有一个提要相互依赖,因此每个提要的顺序处理可以并行

下面是一个带有一个整数馈送的快速脏模型,它只是以大约1.5K/秒的速率将整数推入端口,然后使用CCR迭代器将其取出,以保持有序处理保证

class Program
{
    static Dispatcher dispatcher = new Dispatcher();
    static DispatcherQueue dispatcherQueue = 
       new DispatcherQueue("DefaultDispatcherQueue", dispatcher);
    static Port<int> intPort = new Port<int>();

    static void Main(string[] args)
    {
        Arbiter.Activate(
            dispatcherQueue,
            Arbiter.FromIteratorHandler(new IteratorHandler(ProcessInts)));

        int counter = 0;
        Timer t = new Timer( (x) => 
            { for(int i = 0; i < 1500; ++i) intPort.Post(counter++);}
              , null, 0, 1000);

        Console.ReadKey();
    }

    public static IEnumerator<ITask> ProcessInts()
    {
        while (true)
        {
            yield return intPort.Receive();
            int currentValue;
            if( (currentValue = intPort) % 1000 == 0)
            {
                Console.WriteLine("{0}, Current Items In Queue:{1}", 
                  currentValue, intPort.ItemCount);
            }
        }
    }
}
类程序
{
静态调度程序=新调度程序();
静态DispatcherQueue DispatcherQueue=
新的DispatcherQueue(“DefaultDispatcherQueue”,dispatcher);
静态端口intPort=新端口();
静态void Main(字符串[]参数)
{
仲裁人,激活(
dispatcherQueue,
FromIteratorHandler(新的IteratorHandler(ProcessInts));
int计数器=0;
定时器t=新定时器((x)=>
{for(inti=0;i<1500;++i)intPort.Post(counter++);}
,空,0,1000);
Console.ReadKey();
}
公共静态IEnumerator ProcessInts()
{
while(true)
{
返回intPort.Receive();
int电流值;
如果((currentValue=intPort)%1000==0)
{
WriteLine({0},队列中的当前项:{1}),
currentValue、intPort.ItemCount);
}
}
}
}
令我非常惊讶的是,CCR无法跟上Corei7机箱的速度,队列大小无限制地增长。在另一个测试中,在负载或~100 Post/秒的情况下,测量从Post()到Receive()的延迟,每个批次中第一个Post()到Receive()之间的延迟约为1ms


我的模型有什么问题吗?如果是这样,使用CCR做这件事的更好方法是什么?

是的,我同意,这确实看起来很奇怪。您的代码一开始似乎执行得很顺利,但在执行了几千项之后,处理器的使用率上升到了性能非常低下的地步。这让我感到不安,并表明框架中存在一个问题。在玩了你的代码之后,我真的不知道为什么会这样。我建议把这个问题带到研究中心,看看你能不能让George Chrysanthakopoulos(或其他CCR大脑之一)告诉你问题出在哪里。然而,我可以推测,您的代码目前的效率非常低

处理从端口“弹出”项目的方式效率非常低。本质上,每次端口中有消息时,迭代器都会被唤醒,并且它只处理一条消息(尽管端口中可能还有数百条消息),然后挂起
yield
,同时将控制传递回框架。当接收端导致迭代器再次“唤醒”时,许多消息已经填满了端口。从调度器中抽出一个线程来只处理一个项目(当许多项目同时堆积起来时),几乎肯定不是获得良好吞吐量的最佳方法

我修改了您的代码,以便在屈服之后,我们检查端口,看看是否还有其他消息排队,并对它们进行处理,从而在我们屈服于框架之前完全清空端口。我还对您的代码进行了一些重构,以使用
CcrServiceBase
,从而简化了您正在执行的某些任务的语法:

internal class Test:CcrServiceBase
{
    private readonly Port<int> intPort = new Port<int>();
    private Timer timer;
    public Test() : base(new DispatcherQueue("DefaultDispatcherQueue",
                                             new Dispatcher(0,
                                                            "dispatcher")))
    {

    }

    public void StartTest() {
        SpawnIterator(ProcessInts);
        var counter = 0;
        timer = new Timer(x =>
                          {
                              for (var i = 0; i < 1500; ++i)
                                  intPort.Post(counter++);
                          }
                          ,
                          null,
                          0,
                          1000);
    }

    public IEnumerator<ITask> ProcessInts()
    {
        while (true)
        {
            yield return intPort.Receive();
            int currentValue = intPort;
            ReportCurrent(currentValue);
            while(intPort.Test(out currentValue))
            {
                ReportCurrent(currentValue);
            }
        }
    }

    private void ReportCurrent(int currentValue)
    {
        if (currentValue % 1000 == 0)
        {
            Console.WriteLine("{0}, Current Items In Queue:{1}",
                              currentValue,
                              intPort.ItemCount);
        }
    }
}
内部类测试:CcrServiceBase
{
专用只读端口intPort=新端口();
私人定时器;
公共测试():基本(新DispatcherQueue(“DefaultDispatcherQueue”),
新调度程序(0,
“调度员”))
{
}
公共无效开始测试(){
生成迭代器(ProcessInts);
var计数器=0;
计时器=新计时器(x=>
{
对于(变量i=0;i<1500;++i)
intPort.Post(计数器++);
}
,
无效的
0,
1000);
}
公共IEnumerator ProcessInts()
{
while(true)
{
返回intPort.Receive();
int currentValue=intPort;
报告当前值(currentValue);
while(输入端口测试(输出电流值))
{
报告当前值(currentValue);
}
}
}
私有void报告当前(int currentValue)
{
如果(当前值%1000==0)
{
WriteLine({0},队列中的当前项:{1}),
当前值,
intPort.ItemCount);
}
}
}
或者,您可以完全取消迭代器,因为它在您的示例中没有很好地使用(尽管我不完全确定这对处理顺序有什么影响):

内部类测试:CcrServiceBase
{
专用只读端口intPort=新端口();
私人定时器;
公共测试():基本(新DispatcherQueue(“DefaultDispatcherQueue”),
新调度程序(0,
“调度员”))
{
}
公共无效开始测试()
{
激活(
仲裁人接收(正确,
intPort,
i=>
{
报告当前(i);
int电流值;
while(输入端口测试(输出电流值))
{
报告当前值(currentValue);
}
internal class Test : CcrServiceBase
{
    private readonly Port<int> intPort = new Port<int>();
    private Timer timer;

    public Test() : base(new DispatcherQueue("DefaultDispatcherQueue",
                                             new Dispatcher(0,
                                                            "dispatcher")))
    {

    }

    public void StartTest()
    {
        Activate(
            Arbiter.Receive(true,
                            intPort,
                            i =>
                            {
                                ReportCurrent(i);
                                int currentValue;
                                while (intPort.Test(out currentValue))
                                {
                                    ReportCurrent(currentValue);
                                }
                            }));
        var counter = 0;
        timer = new Timer(x =>
                          {
                              for (var i = 0; i < 500000; ++i)
                              {
                                  intPort.Post(counter++);
                              }
                          }
                          ,
                          null,
                          0,
                          1000);
    }



    private void ReportCurrent(int currentValue)
    {
        if (currentValue % 1000000 == 0)
        {
            Console.WriteLine("{0}, Current Items In Queue:{1}",
                              currentValue,
                              intPort.ItemCount);
        }
    }
}