0

目前我有使用 HttpWebRequest/Response 的多线程下载器类。一切正常,速度超级快,但是..问题是数据在下载到另一个应用程序时需要流式传输。这意味着它必须以正确的顺序流式传输,首先是第一个块,然后是队列中的下一个。目前我的下载器类是同步的,Download() 返回 byte[]。例如,在我创建的异步多线程类中,列出了 4 个空元素(用于插槽),并使用 Download() 函数将插槽的每个索引传递给每个线程。这模拟了同步,但这不是我需要的。我应该如何做队列的事情,以确保数据在第一个块开始下载后立即流式传输。

4

3 回答 3

2

如果您的问题是关于如何确定哪个线程正在下载第一个块以及第一个块何时可以使用,请使用每个线程的事件并跟踪您已分配给哪些线程的块。跟踪您传递给第一个线程的事件(将下载第一块数据),传递给第二个线程的事件(用于第二块数据)等。拥有主线程或另一个后台线程(避免阻塞 UI 线程),等待第一个事件。当第一个线程完成下载其块时,它设置/发出第一个事件。正在等待的线程随后将被唤醒并可以使用第一块数据。

其他下载线程也可以做同样的事情,在完成时发出各自的事件信号。使用手动重置事件,以便即使没有人在等待事件,该事件也将保持信号状态。当需要数据块顺序的线程处理完第一个数据块时,它可以等待第二个事件。如果第二个事件已经发出信号,那么等待将立即返回,线程可以开始处理第二个数据块。

对于非常大的下载,您可以以循环方式重用事件和线程。它们完成的顺序并不重要,只要消耗数据块的线程按顺序消耗它们并按顺序等待相应的事件即可。

如果你聪明而小心,你可能只使用一个事件就可以完成所有这些:创建一个全局数据块指针/对象数组,最初设置为 null,工作线程下载数据块并将完成的块分配给它们各自的插槽在全局数组中,然后发出共享事件的信号。消费者线程保留一个数据块计数器,以便它知道接下来需要处理哪个数据块,等待共享事件,并在收到信号时查看全局数组中的下一个槽,以查看数据是否已出现在那里。如果顺序的下一个槽中仍然没有数据,则消费者线程返回等待事件。您还需要一种方法让工作线程知道他们接下来应该下载哪个数据块 - 受互斥锁保护或使用 interlockedadd/exchange 访问的全局计数器就足够了。

于 2010-05-06T17:41:04.490 回答
0

你能展示你下载的代码,以及你启动多个异步线程的代码吗?

也许我没有完全理解你的场景,但如果我是你,我会使用 Async(beginRead on the responseStream)。然后我会做以下......

void StartReading(Stream responseStream)
{
    byte [] buffer = new byte[1024];
    Context ctx = new Context();
    ctx.Buffer = buffer;
    ctx.InputStream = responseStream;
    ctx.OutputStream = new MemoryStream(); // change this to be your output stream

    responseStream.BeginRead(buffer, 0, buffer.Length; new AsyncCallback(ReadCallback), ctx);
}

void ReadCallback(IAsyncResult ar)
{
    Context ctx = (Context)ar.AsyncState;
    int read = 0;
    try {
        read = ctx.InputStream.EndRead(ar);
        if (read > 0)
        {
            ctx.OutputStream.Write(ctx.Buffer, 0, read);
            // kick off another async read
            ctx.InputStream.BeginRead(ctx.Buffer, 0, ctx.Buffer.Length, new AsyncCallback(ReadCallback), ctx);
        } else {
            ctx.InputStream.Close();
            ctx.OutputStream.Close();
        }
     } catch {
     }
}

}
于 2010-05-06T17:10:42.623 回答
0

要创建同步的多线程下载器,您需要创建正确的数据结构,而且您需要的不仅仅是byte[]数据。

脚步:

  1. 根据内容的大小或固定大小的内容下载器将您的下载分成多个块,每个线程下载约 500KB。
  2. 启动线程时,指定块索引 - 第 1 部分、第 2 部分等
  3. 当下载可用时,根据块索引对齐最终内容。

如果有兴趣,您可能想看看prozilla(C,基于 Linux -at)或 Axel 的代码。

于 2010-05-06T11:58:47.003 回答