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

本文关键字:运行 操作 线程 任务 | 更新日期: 2023-09-27 18:10:51

我正在录制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));
    }
 }

EDIT: The Play Method

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时,我都试图使用它,但它总是出现问题。

基本上,寻找一种方法,使一个线程/任务的工作将只运行这些操作,而不运行其他操作,而不必每次都新建线程。

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

任何想法吗?我已经纠结了一段时间了…

谢谢!

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

正确的方法是创建第二个线程并通过ConcurrentQueue传递数据,您可以查看msdn示例。

但是这需要大量的手工多线程工作。我个人建议你看看TPL数据流,这是一个非常棒的框架,对于这样的任务

下面是一个如何创建和使用TPL数据流的快速示例
// 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中以先进先出的方式异步解析。有几种类型的块,如TransformBlock<in,out>BatchBlock,它们生成数据数组。我建议您阅读手册,TPL Dataflow可能相当强大。

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

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

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

黄金法则是——衡量。概要文件。找出为什么你被延误了。Task基础架构实际上非常快,所以它不太可能是瓶颈。猜测不会让你走得太远,特别是如果你对这类问题没有太多经验的话。