[英]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.QueueUserWorkItem
和Parallel.Invoke
都使用線程池。 通過 TCP 發送幀顯然很慢,並且新任務在線程池中排隊的速度比線程再次空閑的速度要快,並且您很快就會耗盡線程池。
更好的方法是將所有幀排隊到本地隊列ConcurrentQueue<t>
中,並讓一些線程消耗隊列並將幀發送到服務器。 通過這種方式,您將能夠更快地從設備讀取幀(更高的 FPS)。 缺點是停止接收幀后,您仍然需要等待所有幀都發送到服務器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.