首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C#问题中的多线程下载器

C#问题中的多线程下载器
EN

Stack Overflow用户
提问于 2010-05-06 18:43:08
回答 3查看 1.7K关注 0票数 0

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-05-07 01:41:04

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

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

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

如果您够聪明和谨慎,您可能只需要使用一个事件就可以完成所有这些工作:创建一个数据块指针/对象的全局数组,初始设置为null,工作线程下载数据块并将完成的数据块分配给全局数组中各自的槽,然后向共享事件发送信号。使用者线程保留一个数据块计数器,这样它就知道下一步需要处理哪个数据块,等待共享事件,并在收到信号时查看全局数组中的下一个槽,看看数据是否已经出现在那里。如果在序列中的下一个槽中仍然没有数据,使用者线程将返回等待事件。您还需要一种让工作线程知道下一步应该下载哪个数据块的方法-由互斥锁保护的全局计数器或使用interlockedadd/exchange访问的全局计数器就足够了。每个工作线程递增全局计数器并下载该数据块编号,并将结果分配给全局数据块列表中的第n个槽。

票数 2
EN

Stack Overflow用户

发布于 2010-05-06 19:58:47

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

步骤:

  1. 根据内容的大小或每个线程下载的固定大小的内容下载程序将您的下载分成多个区块。
  2. 启动线程时,指定chunk-index -1 part、specify等
  3. 当下载可用时,根据区块索引对齐最终内容。

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

票数 0
EN

Stack Overflow用户

发布于 2010-05-07 01:10:43

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

也许我没有完全理解你的场景,但如果我是你,我会使用异步(responseStream上的BeginRead)。然后,我将执行以下操作...

代码语言:javascript
运行
复制
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 {
     }
}

}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2780414

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档