1

サーバーからライブ ビデオをストリーミングするために、H.264 MediaStreamSource 実装を利用する Silverlight アプリケーションを作成しています。フレームごとにサンプルを読み取るマルチパートストリーマーを作成しました。

ローカル マシンで実行されているサーバーに接続すると、ReadHeaders() 関数で応答ストリームから 2 番目のバイトを読み取るのに 12 秒かかります。したがって、基本的にはホストに即座に接続し、1 バイトを正常に読み取り、後続の 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();
    }

編集: これは 2 つのスレッドのコール スタックです。

Worker Thread Worker Thread GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders Normal [スリープ中、待機中、参加中]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x21 バイト
mscorlib.dll!System.Threading.WaitHandle.WaitOne(長いタイムアウト、bool exitContext) + 0x21 バイト
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int ミリ秒タイムアウト、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[] バッファー、int オフセット、int カウント) + 0x38 バイト
mscorlib.dll!System.IO.Stream.ReadByte() + 0x28 バイト
mscorlib.dll!System.IO.BinaryReader.ReadByte() + 0x1d バイト
GenIIIWebClient!GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders(System.IO.BinaryReader リーダー) 行201 + 0x19 バイト
GenIIIWebClient!GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.OnGetResponse(System.IAsyncResult res) 126 行目 + 0xf バイト
System.Windows.dll!System.Net.Browser.ClientHttpWebRequest.InvokeGetResponseCallback.AnonymousMethod__18(オブジェクト状態 2) + 0x11 バイト
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(オブジェクト状態) + 0x3e バイト
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 ワーカー スレッド ワーカー スレッド [スリープ、待機、または参加中] 通常 [スリープ、待機、または参加中]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long
mscorlib.dll!System.Threading.WaitHandle.WaitOne(長いタイムアウト、bool exitContext) + 0x21 バイトmscorlib.dll
!System.Threading.WaitHandle.WaitOne(int ミリ秒タイムアウト、bool exitContext) + 0x1f バイト
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0x10 バイト
System.Windows.dll!MS.Internal.InternalNetworkStream.ReadOperation(オブジェクトの状態) + 0x8a バイト
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(オブジェクトの状態) + 0x3e バイト
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。それに集中してください。プロジェクトの種類によって、いくつかのスレッド処理が異なる場合があります。

Sleep(1) を指定する代わりに、waitHandle を使用してみましたか?

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
 }
}

以下の行に対する私の 2 番目の提案は、最初のリスト サイズを与えることです。

リスト < バイト > バッファ = 新しいリスト < バイト >();

List<> 型の初期サイズは、配列サイズなどの制限を意味しません。定義済みのサイズを指定しない場合、List 自体がサイズ変更されます。したがって、予想される数を与えることはプラスです。

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