Silverlight HttpWebRequest BinaryReader вторая операция чтения всегда занимает много времени (12 секунд)

Я создаю приложение 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();
    }

Изменить: вот стек вызовов двух потоков.

Unflagged 5096 5 Рабочий поток Рабочий поток [В спящем режиме, ожидании или присоединении] Нормальный [В спящем режиме, ожидании или присоединении]
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 байт
mscorlible.dll! System.Threading. .WaitOne (int millisecondsTimeout, 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.QueueUserWorkItem. Threading.IThreadPoolWorkItem.ExecuteWorkItem () + 0x5a байтов
mscorlib.dll! System.Threading.ThreadPoolWorkQueue.Dispatch () + 0x1b3 байтов
mscorlib.dll! > [Переход от собственного к управляемому]
[Переход домена приложения]
[Переход от собственного к управляемому]

Отсюда трудно увидеть настоящую причину, но это может быть что-то связанное с управлением потоками. Первый подозреваемый, которого я здесь вижу, -

        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
        }
. Сосредоточьтесь на этом. Возможно, некоторые элементы потоковой передачи различаются для разных типов проектов.


person steji113    schedule 04.09.2014    source источник


Ответы (1)


Вы пробовали использовать 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 ‹> НЕ означает ограничение такого размера массива. Если вы не укажете предопределенный размер, список изменится сам. Так что указание ожидаемого числа - это плюс.

Я просто попробовал инициализацию списка, это не сильно улучшило ситуацию. Я отредактировал свой исходный вопрос, добавив стеки вызовов двух потоков. Они оба застряли в вызовах WaitOne (), но я не знаю, кого ждет InternalNetworkStream?

List<byte> buffer = new List<byte>(1024...etc);
person Davut Gürbüz    schedule 05.09.2014
comment
Я не ожидал большого влияния на list Init. Просто предложили. Я не вижу вашего редактирования (потому что у меня сейчас нет компьютера, я использую телефон). Я могу предположить, что WaitOne вызвал из спящего режима. Не используйте WaitOne или Sleep, попробуйте мое первое предложение. 1 мс сна - это не лучший способ для других потоков. Вы должны использовать сброс и настройку. Особенно, если вы какое-то время зацикливаетесь. - person steji113; 05.09.2014
comment
Рабочий поток Рабочий поток GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders Нормальный [В спящем режиме, подождите или присоединитесь]
mscorlib.dll! System.Threading.WaitHandle.InternalWaitOne (System.Runtime.InteropServices. hasThreadAffinity, bool exitContext) + 0x21 байт
mscorlib.dll! System.Threading.WaitHandle.WaitOne (длинный тайм-аут, bool exitContext) + 0x21 байт
mscorlib.dll! System.Threading.WaitHandle.WaitOne (int миллисекундыTimeout 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 байт
mscorlib.dll! System.IO.Stream.ReadByte () + 0x28 байт
mscorlib.dll! System.IO.BinaryReader.ReadByte () + 0x1d байт
GenIIIWebClient! GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.ReadHeaders (System.ReadHeaders .IO.BinaryReader reader) Строка 201 + 0x19 байт
GenIIIWebClient! GenIIIWebClient.CVRESTLib.HttpMultipartStreamer.OnGetResponse (System.IAsyncResult res) Строка 126 + 0xf байтов
System.Windows.dll! System.Net.Browser.ClientHttpWeb .InvokeGetResponseCallback.AnonymousMethod__18 (состояние объекта2) + 0x11 байт
mscorlib.dll! System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (состояние объекта) + 0x3e байта
mscorlib.dll! .ExecutionContext ExecutionContext, обратный вызов System.Threading.ContextCallback, состояние объекта, bool preserveSyncCtx) + 0x97 байтов
mscorlib.dll! System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () + 0x5a байт
mscorlib.dll! System.Threading.ThreadPoolWorkQueue.Dispatch () + 0x1bor3 bytes.dll! Threading._ThreadPoolWaitCallback.PerformWaitCallback () + 0x5 байт
[Переход от собственного к управляемому]
[Переход домена приложения]
[Переход от собственного к управляемому] - person Davut Gürbüz; 05.09.2014