1

我正在创建一个 Silverlight 应用程序,该应用程序利用 H.264 MediaStreamSource 实现从服务器流式传输实时视频。我有一个我编写的 Multipart 流媒体,它逐帧读取样本。

当我连接到在我的本地计算机上运行的服务器时,需要 12 秒才能从 ReadHeaders() 函数中的响应流中读取第二个字节。所以基本上它会立即连接到主机,成功读取一个字节,随后的 ReadByte() 块(如果您查看调用堆栈的位置,它位于另一个线程中:System.Windows.dll!MS.Internal.InternalNetworkStream.ReadOperation (对象状态))。每次我对此进行测试时,它始终需要 12 秒。一旦这段时间过去了,所有后续读取都会立即进行,并且应用程序运行良好。如果我在一个简单的 .NET 控制台应用程序中使用相同的代码,则没有 12 秒的延迟。

知道是什么原因造成的吗?

        byte[] imgBuf = new byte[ChunkSize * ChunkSize];
        HttpWebRequest req = (HttpWebRequest)res.AsyncState;
        int contentLength = 0;
        try
        {
            HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(res);
            // notify delegate of main headers

            // get the response stream and start reading
            BinaryReader reader = new BinaryReader(resp.GetResponseStream());
            Dictionary<string, string> headers;
            while (m_Running)
            {
                // read multipart response headers and notify delegate
                headers = ReadHeaders(reader);

                // check if end of stream
                if (headers.ContainsKey(CustomHeaders.EndOfStreamHeader) 
                    && headers[CustomHeaders.EndOfStreamHeader] != null
                    && String.Compare(headers[CustomHeaders.EndOfStreamHeader], "yes") == 0)
                {
                    // notify delegate if end of stream has been reached
                }
                // determine length of data to read
                string cl = headers["Content-Length"];
                if (cl != null)
                {
                    contentLength = Int32.Parse(cl);
                }
                byte[] data = reader.ReadBytes(contentLength);

                if (data.Length > 0)
                {
                    // notify delegate of multipart data
                }
                // Yield to other threads waiting to be executed
                System.Threading.Thread.Sleep(1);
            }
            reader.Close();
            resp.Close();
            req.Abort();
        }
        catch (Exception ex)
        {
            // notify delegate of any errors that occurred
        }

ReadHeaders() 函数:

    private Dictionary<string, string> ReadHeaders(BinaryReader reader)
    {
        List<byte> buffer = new List<byte>();
        while (m_Running)
        {
            buffer.Add(reader.ReadByte());
            if (buffer.EndsWith(EndOfHeaderBytes))
            {
                break;
            }
            // Yield to other threads waiting to be executed
            System.Threading.Thread.Sleep(1);
        }
        return buffer.ToHeadersDictionary();
    }

编辑:这是两个线程的调用堆栈。

工作线程 工作线程 GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders 正常 [处于睡眠、等待或加入]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x21 字节
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x21 字节
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x1f 字节
mscorlib.dll !System.Threading.WaitHandle.WaitOne() + 0x10 字节
System.Windows.dll!MS.Internal.InternalNetworkStream.EndRead(System.IAsyncResult asyncResult) + 0x40 字节
System.Windows.dll!MS.Internal.InternalNetworkStream.Read(byte[] buffer, int offset, int count) + 0x38 bytes
mscorlib.dll!System.IO.Stream.ReadByte() + 0x28 bytes
mscorlib.dll!System.IO.BinaryReader.ReadByte() + 0x1d bytes
GenIIIWebClient!GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders(System.IO.BinaryReader reader) Line 201 + 0x19 字节
GenIIIWebClient!GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.OnGetResponse(System.IAsyncResult res) 第 126 行 + 0xf 字节
System.Windows.dll!System.Net.Browser.ClientHttpWebRequest.InvokeGetResponseCallback.AnonymousMethod__18(object state2) + 0x11 bytes
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state) + 0x3e bytes
mscorlib.dll!System.Threading。 ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback 回调, 对象状态, bool preserveSyncCtx) + 0x97 字节
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x5a 字节
mscorlib .dll!System.Threading.ThreadPoolWorkQueue.Dispatch() + 0x1b3 字节
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x5 字节
[本地到托管转换]
[Appdomain 转换]
[本地到托管转换]

未标记 5096 5 Worker Thread Worker Thread [处于睡眠、等待或加入] 正常 [处于睡眠、等待或加入]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x21 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x21 bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x1f 字节
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0x10 字节
System.Windows.dll!MS.Internal.InternalNetworkStream.ReadOperation(object state) + 0x8a bytes
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state) + 0x3e bytes
mscorlib.dll!System.Threading.ExecutionContext.Run( System.Threading.ExecutionContext executionContext、System.Threading.ContextCallback 回调、对象状态、bool preserveSyncCtx) + 0x97 字节
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() + 0x5a 字节
mscorlib.dll!System .Threading.ThreadPoolWorkQueue.Dispatch() + 0x1b3 字节
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() + 0x5 字节
[本地到托管转换]
[Appdomain 转换]
[本地到托管转换]

4

1 回答 1

1

从这里很难看出真正的原因,但它可能与线程管理有关。我在这里看到的第一个嫌疑人是m_Running。专注于此。也许一些线程的东西会因项目类型而异。

您是否尝试过使用 waitHandle 而不是使用 Sleep(1),

ManualResetEvent waitHandle = new ManualResetEvent(false);

while(true)
{
  waitHandle.Wait();
  waitHandle.Reset();

  while(ThereIsAJobToExecute)
 {
    // Process the jobs
    // You should waitHandle.Set() in a callback or when you read it
 }
}

我对以下行的第二个报价是给出初始列表大小

列表<字节>缓冲区=新列表<字节>();

List<> 类型的初始大小并不意味着限制这样的数组大小。如果你不给一个预定义的大小 List 会自行调整大小。所以给出一个预期的数字是一个加号。

List<byte> buffer = new List<byte>(1024...etc);
于 2014-09-05T07:43:54.540 回答