Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 如何平衡和并行处理多个连续数据流_.net_Multithreading_Performance_.net 4.0_Task Parallel Library - Fatal编程技术网

.net 如何平衡和并行处理多个连续数据流

.net 如何平衡和并行处理多个连续数据流,.net,multithreading,performance,.net-4.0,task-parallel-library,.net,Multithreading,Performance,.net 4.0,Task Parallel Library,我有一个必须尽快处理的单一数据流。单个流包含多达200个源的数据。并非所有的数据源都会产生相同数量的数据,而且速率可能会有所不同 作为最初的尝试,我决定创建10个长时间运行的任务(有点基于服务器规范,双四核)。每个任务都将从块集合中读取。在开始之前,我创建了一个映射,以便在入站流上接收数据时,我知道要将该数据源添加到哪个BlockingCollection 我认为,问题在于,我不知道哪一个数据源会产生最多的数据,事实上,随着时间的推移,这种情况会发生变化。我看到一些集合非常空,而另一些则接收到更

我有一个必须尽快处理的单一数据流。单个流包含多达200个源的数据。并非所有的数据源都会产生相同数量的数据,而且速率可能会有所不同

作为最初的尝试,我决定创建10个长时间运行的任务(有点基于服务器规范,双四核)。每个任务都将从块集合中读取。在开始之前,我创建了一个映射,以便在入站流上接收数据时,我知道要将该数据源添加到哪个BlockingCollection

我认为,问题在于,我不知道哪一个数据源会产生最多的数据,事实上,随着时间的推移,这种情况会发生变化。我看到一些集合非常空,而另一些则接收到更多的更新

如果我有8个可用的硬件线程,并且我已经创建了大约10个队列,并且任务没有绑定到一个线程(同样不确定
TaskCreationOptions.longlunning
)是否为真,然后,即使一个队列不忙,另一个繁忙的队列也不能利用备用线程,因为理论上,我可能会处理一段无序的数据

我是否应该为每个源创建一个任务并阻塞集合,这样TPL就可以充分利用可用的线程,因为数据是最隔离的

我的另一个选择是以某种方式利用过去的统计数据和各种外部/人类信息,了解如何最好地在有限的封锁集合/任务集合中传播源,然后随着时间调整映射

我希望我已经充分解释了我的情况

我正在使用一个类来封装

我有一个可以被可视化为40+个交错的流,如果分割,这些流可以被同时处理(只要每个流保持在它自己的序列中),但是有比可用硬件线程多得多的流

编辑-尝试澄清我的查询
试图澄清我在寻找什么。我目前正在有效地将源划分为子组,并将每个组分配给它自己的队列。我的问题是:要创建多少组?如果我有200个源,我是否应该创建200个组(即200个任务和阻塞集合),然后让TPL像疯子一样四处运行,在每个任务获得cpu时间时,尽可能地分配线程。还是最好为每个底层硬件线程分配一个组?

我相信管道方法会对您有所帮助

管道模式使用并行任务和并发队列来 处理一系列输入值。每个任务执行一个阶段的任务 管道和队列充当缓冲区,允许 要并发执行的管道,即使值为 按顺序处理。您可以将软件管道视为类似的管道 到工厂的装配线,装配线中的每个项目 分阶段施工。部分组装的项目从中传递 从一个装配阶段到另一个装配阶段。装配线的输出发生 与输入的顺序相同

请参阅以下MSDN文件和示例:


如果您为每个源创建了一个
任务和一个队列,只要该
任务在队列为空时完成,就应该可以工作。您将肯定地知道,在一个源中对项目的排序是维护的,并且在必要时您应该拥有完整的CPU利用率。但是,如果当前所有线程都在处理,并且新数据来自低频源,则在处理该数据之前,您可能需要等待很长时间

如果这对您来说是一个问题,您应该自己管理处理的确切顺序,而不是依赖于任务。要做到这一点,您可以为每个源分别设置一个全局队列和一个本地队列。要维护订单,全局队列或当前处理中最多只能有一个数据项。处理项目时,如果可能,将项目从正确的本地队列移动到全局队列。这样,您应该获得更公平的数据处理顺序

代码可能如下所示:

class SourcesManager<T>
{
    private readonly BlockingCollection<Tuple<T, Source<T>>> m_queue =
        new BlockingCollection<Tuple<T, Source<T>>>();

    public Source<T> CreateSource()
    {
        return new Source<T>(m_queue);
    }

    // blocks if no items are available and Complete() hasn't been called
    public bool TryProcess(Action<T> action)
    {
        Tuple<T, Source<T>> tuple;
        if (m_queue.TryTake(out tuple, Timeout.Infinite))
        {
            action(tuple.Item1);
            tuple.Item2.TryDequeue();
            return true;
        }

        return false;
    }

    public void Complete()
    {
        m_queue.CompleteAdding();
    }
}

class Source<T>
{
    private readonly Queue<T> m_localQueue = new Queue<T>();
    private readonly BlockingCollection<Tuple<T, Source<T>>> m_managerQueue;
    private volatile bool m_managerHasData = false;

    internal Source(BlockingCollection<Tuple<T, Source<T>>> managerQueue)
    {
        m_managerQueue = managerQueue;
    }

    public void Enqueue(T data)
    {
        lock (m_localQueue)
        {
            if (!m_managerHasData)
            {
                m_managerQueue.Add(Tuple.Create(data, this));
                m_managerHasData = true;
            }
            else
                m_localQueue.Enqueue(data);
        }
    }

    internal bool TryDequeue()
    {
        lock (m_localQueue)
        {
            if (m_localQueue.Count == 0)
            {
                m_managerHasData = false;
                return false;
            }

            m_managerQueue.Add(Tuple.Create(m_localQueue.Dequeue(), this));
            return true;
        }
    }
}
类源管理器
{
私有只读阻止集合m_队列=
新BlockingCollection();
公共源CreateSource()
{
返回新源(m_队列);
}
//如果没有可用项且尚未调用Complete(),则阻止
公共bool TryProcess(操作)
{
元组;
if(m_queue.TryTake(out tuple,Timeout.Infinite))
{
动作(tuple.Item1);
tuple.Item2.TryDequeue();
返回true;
}
返回false;
}
公开作废完成()
{
m_queue.CompleteAdding();
}
}
类源
{
私有只读队列m_localQueue=new Queue();
私有只读阻止集合m_managerQueue;
私有易失性bool m_managerHasData=false;
内部源(BlockingCollection Manager队列)
{
m_managerQueue=managerQueue;
}
公共无效排队(T数据)
{
锁定(m_localQueue)
{
如果(!m_managerHasData)
{
m_managerQueue.Add(Tuple.Create(data,this));
m_managerHasData=true;
}
其他的
m_localQueue.Enqueue(数据);
}
}
内部bool TryDequeue()
{
锁定(m_localQueue)
{
如果(m_localQueue.Count==0)
{
m_managerHasData=false;
返回false;
}
添加(Tuple.Create(m_localQueue.Dequeue(),this));
返回true;
}
}
}

我个人会在这里利用TPL数据流,只需定义一个
动作块
,它代表您的工作,并将
缓冲块
链接到它的“前面”,以防止不同制作者过度饱和。那么你所要做的就是把它贴到