2017-06-01 47 views
-1

我试图让我的代码的一部分并行运行,我试图在C#中使用ThreadPool,以避免任何头痛,但似乎我要求太多的池,我的代码实际上它运行得更慢!C#并行处理选项

下面的代码解释了我想要做的事情,我有大量的音频样本(取决于缓冲区大小从512-> 4096的任何地方),需要插入,传播和读取节点(从n = 4到n = 16)。这必须以样本为基础进行,因此我唯一的优化选择是对网络中存在的每个节点采用插入/传播/读取并具有并行操作的部分。该操作在每个游戏帧中调用一次,并且在游戏的整个生命周期中都需要。看一下剖析器,散射操作需要大量的时间,所以它是一个很好的候选者(我已经完成了传统的优化)。目前,我有一个线程池工作人员为一个工作项目中的所有节点完成工作,只是为了启动和运行,但稍后可以拆分工作。

我认为下面的代码的问题是插入到线程池的工作项的频率,我也读过某些地方,线程需要一段时间才能旋转起来,所以如果线程池创建更多,它不neccserally帮助。有没有人有任何其他并行处理方法的建议,或可以发现我的线程池实施的任何错误?

public void propagateNetwork() { 

    int numSampsToConsume = Mathf.min(inSamples.Count,buffersize); 

    for (int i = 0; i < numSampsToConsume; i++) { 
     outVal = 0.0f; 
     inVal = inSamples.Dequeue() * networkInScale; 

     directDelay.write (inVal); 
     directVal = directDelay.read(); 
     directVal *= directAtt; 

     for (j = 0; j < network.Count; j++) { 
      outVal += network [j].getOutgoing(); 
      network [j].inputIncoming (inVal); 
     } 

     ThreadPool.QueueUserWorkItem (scatteringThreadPoolWrapper); 
     scatteringThreadDone.WaitOne(); 

     outVal += directVal; 
     outSamples.Enqueue (outVal); 
    } 
} 

public void scatteringThreadPoolWrapper(object threadConext) { 
    doScatteringForNodeRange (0, network.Count); 
} 

public void doScatteringForNodeRange(int min,int max) { 
    for (int i = min; i < max; i++) { 
     network[i].doScattering (doLateReflections); 
    } 
    scatteringThreadDone.Set(); 
} 
+1

如果你排队然后马上等待,那不就是删除了吗?你不应该排队所有的工作项目,然后等待他们在另一个循环完成?也许考虑用'Parallel.for'替代你的外部? – NetMage

+0

也许我误解了线程池的功能,但我认为我分配给它的每个任务可能都在不同的线程上。因此总体来说它会更快完成?我知道在示例代码中,我还没有将工作分解,这只是一个测试,看它是否可行。我需要等待,因为每个样本必须在完成传播之前完成传播,出于同样的原因,并行是不可能的。 – Rampartisan

+0

每个任务可能位于不同的线程上,但是如果您将任务发送到另一个线程,然后等待在主线程上运行另一个任务之前取回答案,那么当然您会更慢。您仍然一次只运行一个线程,但是您添加了创建线程和跨线程通信的开销。 – NetMage

回答

0

也许使用Parallel.for会工作吗?我在每个循环迭代中都创建了一些本地变量,但我不知道这些操作都在做什么,以及如果这些操作可能会导致问题(如果并行运行)。

public void propagateNetwork() { 
    int numSampsToConsume = Mathf.min(inSamples.Count,buffersize); 

    Parallel.for(0, numSampsToConsume, i => { 
     var outVal = 0.0f; 
     var inVal = inSamples.Dequeue() * networkInScale; 

     directDelay.write (inVal); 
     var directVal = directDelay.read(); 
     directVal *= directAtt; 

     Parallel.for(0, network.Count, j => { 
      outVal += network [j].getOutgoing(); 
      network [j].inputIncoming (inVal); 
     }); 

     doScatteringForNodeRange (0, network.Count); 

     outVal += directVal; 
     outSamples.Enqueue (outVal); 
    }); 
} 
+0

刚刚实现了最内层的并行,它仍然需要比正常的循环更长的循环!不同于线程池会尝试在池中重复使用尽可能多的线程,并且只在需要时才创建新线程吗?我认为我的主要问题是旋转新线程花费的时间太长(如果这是平行进行的) 最外面的循环不能平行,因为每个样本必须按顺序传播。 – Rampartisan

+0

并行操作的嵌套可能会导致速度下降,但它仍然是在调用点(例如,调制解调器)的“同步”操作。doScatteringForNodeRange在内部循环完成之前不会运行),这意味着每个外部循环都在管理并行状态,产生其他并行任务并暂停。理想情况下,你需要一个循环来完成一切,如下所示:1.查看是否可以扩展内部循环以成为主要驱动程序,以及2.避免任何共享状态访问。 – Clint

+0

通过并行操作的嵌套你是否意味着在这个asnwer中的2个并行?因为正如我之前提到的,我不能将外部看作平行的,因此并没有像这样实施。所有音频样本都必须按顺序处理,只有内部操作是并行性的候选对象。 但是你关于交换内部和外部循环的观点很有趣,我会考虑一下,如果这是可能的! – Rampartisan