同时执行多个FTP请求

时间:2014-12-22 15:58:31

标签: c# ftp backgroundworker

我有一个FTP远程文件列表,我试图检索每个文件的文件大小。这些文件位于不同的服务器上。

我有一个方法GetFileSize,它运行得很好。目前,我通过一个简单的循环一次处理每个项目的列表。

考虑到文件大小的简单请求不会占用大量带宽,我想同时异步执行所有请求。

我尝试为每个项目使用BackgroundWorker个数组,但结果是只处理了列表中的最后一项:

public static void GetFileSizes(List<string> files)
{
    BackgroundWorker[] workers = new BackgroundWorker[files.Count];

    for (int i = 0; i < files.Count - 1; i++)
    {
        workers[i] = new BackgroundWorker();
        workers[i].WorkerReportsProgress = false;
        workers[i].WorkerSupportsCancellation = true;
        workers[i].DoWork += (sender, e) =>
        {
            long size = Ftp.GetSize(files[i]);
            MessageBox.Show(size.ToString());
        };
        workers[i].RunWorkerAsync();
    }
}

还有其他办法吗?

1 个答案:

答案 0 :(得分:1)

您无法确保每个匿名方法都捕获不同的变量。 for循环变量i对于每个匿名方法都是相同的变量。

由于当前线程做得很少,因此在任一工作者完全运行之前完成整个循环的概率非常高。发生这种情况时,变量i处于不符合循环条件的第一个值,即file.Count - 1

按常规编写循环时,循环结尾处的变量值为file.Count,因此异常。

有多种方法可以解决这个问题,但恕我直言最好和最简单的方法是捕获文件名而不是索引。这不仅解决了您的直接问题,还将工作人员与实际的files对象隔离开来,这样如果您在其他地方有错误并在工作人员完成之前修改该对象,则不会影响工作人员。

E.g:

for (int i = 0; i < files.Count - 1; i++)
{
    string file = files[i];

    workers[i] = new BackgroundWorker();
    workers[i].WorkerReportsProgress = false;
    workers[i].WorkerSupportsCancellation = true;
    workers[i].DoWork += (sender, e) =>
    {
        long size = Ftp.GetSize(file);
        MessageBox.Show(size.ToString());
    };
    workers[i].RunWorkerAsync();
}

最后,请不要将WorkerReportsProgressWorkerSupportsCancellation属性设置为true,除非您实际实施工作中的相应行为。

(我假设在您的实际代码中,您不会从工作线程调用MessageBox.Show() ...这也是一个坏主意,至少对于非调试方案而言。)