我最近开始编写我的第一个多线程代码,非常感谢您提出一些意见。
它从缓冲区中传送视频样本,该缓冲区由流解析器在后台填充(超出此问题的范围)。如果缓冲区为空,则需要等到缓冲区级别变得可接受后再继续。
代码适用于 Silverlight 4,删除了一些错误检查:
// External class requests samples - can happen multiple times concurrently
protected override void GetSampleAsync()
{
Interlocked.Add(ref getVideoSampleRequestsOutstanding, 1);
}
// Runs on a background thread
void DoVideoPumping()
{
do
{
if (getVideoSampleRequestsOutstanding > 0)
{
PumpNextVideoSample();
// Decrement the counter
Interlocked.Add(ref getVideoSampleRequestsOutstanding, -1);
}
else Thread.Sleep(0);
} while (!this.StopAllBackgroundThreads);
}
void PumpNextVideoSample()
{
// If the video sample buffer is empty, tell stream parser to give us more samples
bool MyVidBufferIsEmpty = false; bool hlsClientIsExhausted = false;
ParseMoreSamplesIfMyVideoBufferIsLow(ref MyVidBufferIsEmpty, ref parserAtEndOfStream);
if (parserAtEndOfStream) // No more data, start running down buffers
this.RunningDownVideoBuffer = true;
else if (MyVidBufferIsEmpty)
{
// Buffer is empty, wait for samples
WaitingOnEmptyVideoBuffer = true;
WaitOnEmptyVideoBuffer.WaitOne();
}
// Buffer is OK
nextSample = DeQueueVideoSample(); // thread-safe, returns NULL if a problem
// Send the sample to the external renderer
ReportGetSampleCompleted(nextSample);
}
代码似乎运行良好。但是,有人告诉我使用 Thread.Wait(...) 是“邪恶的”:当没有请求样本时,我的代码会不必要地循环,占用 CPU 时间。
我的代码可以进一步优化吗?由于我的类(class)是为需要样本的环境设计的,潜在的“无意义循环”场景是否超过了其当前设计的简单性?
非常感谢评论。
最佳答案
这看起来像经典的生产者/消费者模式。解决此问题的常规方法是使用所谓的阻塞队列。
.net 4.0 版引入了一套高效、精心设计的 concurrent collection classes对于这种类型的问题。我想 BlockingCollection<T>
将满足您当前的需求。
如果您无法访问 .net 4.0,那么有很多网站都包含阻塞队列的实现。我个人的标准引用是 Joe Duffy 的书,Concurrent Programming on Windows .一个好的开始是 Marc Gravell's blocking queue presented here in Stack Overflow .
使用阻塞队列的第一个好处是你可以停止使用繁忙的等待循环,停止对 Sleep()
的 hacky 调用。等等。使用阻塞队列来避免这种代码总是一个好主意。
但是,我发现使用阻塞队列有一个更重要的好处。目前,您用于生成工作项、使用它们和处理队列的代码都是混合在一起的。如果您正确使用阻塞队列,那么您最终会得到更好的分解代码,这些代码将算法的各个组件分开:队列、生产者和消费者。
关于c# - 我可以更好地优化这个并发吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5868794/