繁体   English   中英

在 C# 中的线程中接收帧的最佳方式

[英]Best way of receiving frames in a thread in C#

我在从 HoloLens 接收帧时遇到问题。 基本上我正在捕获帧并使用一个套接字连接将其发送到服务器。 当 HoloLens 使用Task.Run(#send to server call)获取帧时,我曾经将帧发送到服务器,但问题是它在开始时工作正常,但随后每秒帧数 (FPS) 下降到零并且问题我发现它基本上制造了太多线程并且产生了瓶颈(这就是我想出来的)所以现在我所做的是而不是使用Task.Run(#send to server call)我使用Parallel.Invoke(#send to server call) ,但它给出了低 FPS,我发现它的原因是,当它在这个调用调用上工作时,有一些帧到达,导致低 FPS。 我也尝试了 async/await 方法,但仍然发生了同样的瓶颈,并且 FPS 降低到零。 我也尝试使用取消令牌,但也没有用。 这是 function ,它在帧到达 HoloLens 时调用。

    private void ColorFrameReader_FrameArrivedAsync(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
    {
        var frame = sender.TryAcquireLatestFrame();
        if (frame != null)
        {
            SoftwareBitmap originalBitmap = null;
            var inputBitmap = frame.VideoMediaFrame?.SoftwareBitmap;
            if (inputBitmap != null)
            {
                // The XAML Image control can only display images in BRGA8 format with premultiplied or no alpha
                // The frame reader as configured in this sample gives BGRA8 with straight alpha, so need to convert it
                originalBitmap = SoftwareBitmap.Convert(inputBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);                 
                SoftwareBitmap outputBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, originalBitmap.PixelWidth, originalBitmap.PixelHeight, BitmapAlphaMode.Premultiplied);

                //this thread goes to the c++ code and start the TCP communication                
                //var task = Task.Factory.StartNew(() => { ct.ThrowIfCancellationRequested(); _helper.Connect(originalBitmap); }, cts.Token);
                
                ab_func(originalBitmap);
                                                                            
               //System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(_helper.Connect(originalBitmap)));
                //Windows.System.Threading.ThreadPool.RunAsync                    
                //Parallel.Invoke(() => _helper.Connect(originalBitmap));
                //task.Start();
            }

            Interlocked.Increment(ref _frameCount);
        }
    }

    async void ab_func(SoftwareBitmap fr)
    {
       await Task.Run(() => { _helper.Connect(fr); });
    }

以下是有关 C++ 文件的连接方法的更多信息。 _helper基本上是 C++ class 的 object。

void OpenCVHelper::Connect(SoftwareBitmap^ input)
{
  Mat inputMat, outputMat;
  if (!(TryConvert(input)))
  {
      return;
  }
int imgSize = GlobalMat.total() * GlobalMat.elemSize();
//m_OutStream << "GlobalMat.total()  " << GlobalMat.total();
//m_OutStream << "GlobalMat.total()  " << GlobalMat.elemSize();
int i = 1;
//m_OutStream << "i value is  \n"<<i;
auto t0 = std::chrono::system_clock::now();
auto nanosec = t0.time_since_epoch();


if (ConnectSocket == INVALID_SOCKET) {
    //printf("Unable to connect to server!\n");
    //m_OutStream << "Unable to connect to server! 2\n" << WSAGetLastError();
    WSACleanup();
    return;
}
uchar* iptr = GlobalMat.data;
t0 = std::chrono::system_clock::now();
nanosec = t0.time_since_epoch();
m_OutStream << "timestamp before sending of frame " << i++ << " = " << std::chrono::duration_cast<std::chrono::milliseconds>(nanosec).count() << std::endl;


//send the frame to the server
if ((bytes = send(ConnectSocket, (char*)iptr, imgSize, 0)) < 0) {
    //m_OutStream << "bytes = " << bytes << std::endl;
    m_OutStream << "problem 2 ! \n";
    //break;
}

return;
}

这是调试屏幕截图,我说它制造了太多线程并造成瓶颈。 调试截图

显然,瓶颈是通过网络发送帧。 任务、 System.Threading.ThreadPool.QueueUserWorkItemParallel.Invoke都使用线程池。 通过 TCP 发送帧显然很慢,并且新任务在线程池中排队的速度比线程再次空闲的速度要快,并且您很快就会耗尽线程池。

更好的方法是将所有帧排队到本地队列ConcurrentQueue<t>中,并让一些线程消耗队列并将帧发送到服务器。 通过这种方式,您将能够更快地从设备读取帧(更高的 FPS)。 缺点是停止接收帧后,您仍然需要等待所有帧都发送到服务器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM