在任务/线程上运行小操作

时间:2014-07-01 07:20:55

标签: c# multithreading task delay

我正在录制来自IP电话的音频,用c#写作。

我有一个为我捕获的每个数据包运行的方法(很多数据包)。该方法使用有效负载数据填充缓冲区。

public void HandlePayload(byte[] payload, IpV4Address dstIp)
{
    count++;
    // packet from source
    if (dstIp == _dstIp)
    {
        AddPayloadToArray(MuLawDecoder.MuLawDecode(payload), ArrayType.SRC_PCM);
        // Task.Run(() =>AddPayloadToArray(MuLawDecoder.MuLawDecode(payload), ArrayType.SRC_PCM));
    }

    // packet from destination
    if (dstIp == _srcIp)
    {
        AddPayloadToArray(MuLawDecoder.MuLawDecode(payload), ArrayType.DST_PCM);
        // Task.Run(() =>AddPayloadToArray(MuLawDecoder.MuLawDecode(payload), ArrayType.DST_PCM));
    }
 }

编辑:播放方法

public void PlayCall(SkinnyCall call)
{
    Waveout.Play();
    byte[] mixedBuffer = new byte[320];
    while (_playerIndex < call.AudioArrays[(int)ArrayType.Pcm].Length)
    {
        if (_state == PlayerState.Paused || _state == PlayerState.Stopped)
            // call either paused or stopped
            break;
        for (int i = 0; i < 320; i++)
        {
            mixedBuffer[i] = (byte)(call.AudioArrays[(int)ArrayType.Pcm][_playerIndex + i];
        }
        _playerIndex += 320;
        Thread.Sleep(20);
        AddSamples(mixedBuffer);
        ClearByteArray(ref mixedBuffer);
    }
    if (_playerIndex == call.AudioArrays[(int)ArrayType.Pcm])
    {
        // call has finished and Playback is over
        StopCall(call);
        PlaybackEnded();
    }
}

我需要一种方法在不同的线程/任务上运行它,因为当我正常运行它(在同一个线程上)时,一段时间后会有延迟并且它会变大。

每次运行时我都尝试使用Task.run,但它确实存在问题。

基本上,寻找一种方法来让一个线程/任务的工作就是只运行那些操作,而不必每次都运行新线程。

并且每次都能将参数传递给它。

任何想法?一段时间以来一直在努力......

谢谢!

2 个答案:

答案 0 :(得分:1)

执行此操作的正确方法是创建第二个Thread并通过ConcurrentQueue将数据传递到那里,您可以查看msdn示例。

但这需要大量的手动多线程工作。我个人建议你看看TPL Dataflow这个任务非常棒的框架

以下是如何创建和使用TPL Dataflow的快速示例

// Create bufferBlock for store
BufferBlock<byte[]> _inputBufferBytes = new BufferBlock<byte[]>();

// Create action block for job
ActionBlock<byte[]> _inputBufferParcer = new ActionBlock<byte[]>(bytes => ProcessInputBuffer(bytes));

// Link one block to another 
// from [_inputBufferBytes] to [_inputBufferParcer]
_inputBufferBytes.LinkTo(_inputBufferParcer);

...

// add new bytes to buffer
_inputBufferBytes.Post(buffer);

您可以从任何线程自由地将数据发布到BufferBlock,它们将在ActionBlock中以FIFO方式异步解析。有几种块,如TransformBlock<in,out>BatchBlock,它们生成数据数组。我建议你阅读手册,TPL Dataflow可能非常强大。

答案 1 :(得分:0)

您可以使用生产者 - 使用者队列来同步两个线程之间的工作。 BlockingCollection特别使这样的代码变得轻而易举。

但是,您更有可能遇到另一个问题 - 您应该能够在一个线程上实时处理数据。确保性能问题实际上在您认为的位置,测量您在代码的每个部分中丢失的时间。使用Task.Run不是最好的主意,但它可以工作(并且它实际上不会创建新线程 - 它会重用线程池中的线程)。

根据您的内存使用模式,您甚至可能会遇到垃圾收集器的问题。 CLRProfiler会帮助您确定这一点,并且您可能还想调查一下如何使用您传递的byte[]缓冲区 - 如果您实际上没有将其复制到任何地方并且只是通过了对原始缓冲区的引用,多线程意味着您可以在有机会被处理之前重写数据。

黄金法则是 - 衡量。轮廓。找出为什么你得到了延迟。 Task基础设施实际上非常快,因此不太可能是瓶颈。猜测不会让你走得太远,特别是如果你对这类问题没有多少经验。