使用 C# Parallel.ForEach 循环处理 SFTP 文件不处理下载

2023-12-08

我正在使用 Renci SSH.NET 软件包版本 2016。我正在从外部服务器下载文件。我通常每 6 秒就能下载一个文件,当你有数千个文件时,这很糟糕。我最近尝试改变foreach循环到Parallel.ForEach。这样做将文件下载时间更改为 1.5 秒。除了当我检查文件时,它们都是 0 KB,因此它没有下载任何内容。并行循环有什么问题吗?我是 C# 新手,正在尝试缩短下载时间

Parallel.ForEach(summary.RemoteFiles, (f, loopstate) =>
{
    //Are we still connected? If not, reestablish a connection for up to a max of "MaxReconnectAttempts" 
    if (!sftp.IsConnected)
    {
        int maxAttempts = Convert.ToInt32(ConfigurationManager.AppSettings["MaxReconnectAttempts"]);

        StatusUpdate(this, new Types.StatusUpdateEventArgs() { message = "SFTP Service has been connected from remote system, attempting to reconnect (" + sftpConnInfo.Host + ":" + sftpConnInfo.Port.ToString() + remotePath + " - Attempt 1 of " + maxAttempts.ToString() + ")", Location = locationName });

        for (int attempts = 1; attempts <= maxAttempts; attempts++)
        {
            sftp.Connect();

            if (sftp.IsConnected)
            {
                StatusUpdate(this, new Types.StatusUpdateEventArgs() { message = "SFTP Service - Connection reestablished (" + remotePath + ")", Location = locationName });
                break;
            }
            else
            {
                if ((attempts + 1) <= maxAttempts)
                {
                    StatusUpdate(this, new Types.StatusUpdateEventArgs() { message = "SFTP Service still disconnected from remote system, preparing another reconnect attempt (" + sftpConnInfo.Host + ":" + sftpConnInfo.Port.ToString() + remotePath + " - Attempt " + (attempts + 1).ToString() + " of " + maxAttempts.ToString() + ")", Location = locationName });
                    System.Threading.Thread.Sleep(2000);
                }
                else
                {
                    //Max reconnect attempts reached - end the session and ensure the appropriate "failure" workflow is triggered
                    connectionLost = true;
                }
            }
        }
    }

    if (connectionLost)
        loopstate.Break();
       // break;


    totalFileCount++;
    try
    {
      if (!System.IO.File.Exists(localSaveLocation + f.FileName))

        {
            System.Diagnostics.Debug.WriteLine("\tDownloading file " + totalFileCount.ToString() + "(" + f.FileName + ")");

            System.IO.Stream localFile = System.IO.File.OpenWrite(localSaveLocation + f.FileName);
            //Log remote file name, local file name, date/time start
            start = DateTime.Now;
            sftp.DownloadFile(f.FullName, localFile);
            end = DateTime.Now;

            //Log remote file name, local file name, date/time complete (increment the "successful" downloads by 1)
            timeElapsed = end.Subtract(start);
            runningSeconds += timeElapsed.TotalSeconds;
            runningAvg = runningSeconds / Convert.ToDouble(totalFileCount);
            estimatedSecondsRemaining = (summary.RemoteFiles.Count - totalFileCount) * runningAvg;

            elapsedTimeString = timeElapsed.TotalSeconds.ToString("#.####") + " seconds";
            System.Diagnostics.Debug.WriteLine("\tCompleted downloading file in " + elapsedTimeString + " " + "(" + f.FileName + ")");
            downloadedFileCount++;
            ProcessFileComplete(this, new Types.ProcessFileCompleteEventArgs() { downloadSuccessful = true, elapsedTime = timeElapsed.TotalSeconds, fileName = f.FileName, fullLocalPath = localSaveLocation + f.FileName, Location = locationName, FilesDownloaded = totalFileCount, FilesRemaining = (summary.RemoteFiles.Count - totalFileCount), AvgSecondsPerDownload = runningAvg, TotalSecondsElapsed = runningSeconds, EstimatedTimeRemaining = TimeSpan.FromSeconds(estimatedSecondsRemaining) });

            f.FileDownloaded = true;

            if (deleteAfterDownload)
                sftp.DeleteFile(f.FullName);
        }
        else
        {
            System.Diagnostics.Debug.WriteLine("\tFile " + totalFileCount.ToString() + "(" + f.FileName + ") already exists locally");
            downloadedFileCount++;

            ProcessFileComplete(this, new Types.ProcessFileCompleteEventArgs() { downloadSuccessful = true, elapsedTime = 0, fileName = f.FileName + " (File already exists locally)", fullLocalPath = localSaveLocation + f.FileName, Location = locationName, FilesDownloaded = totalFileCount, FilesRemaining = (summary.RemoteFiles.Count - totalFileCount), AvgSecondsPerDownload = runningAvg, TotalSecondsElapsed = runningSeconds, EstimatedTimeRemaining = TimeSpan.FromSeconds(estimatedSecondsRemaining) });
            f.FileDownloaded = true;

            if (deleteAfterDownload)
                sftp.DeleteFile(f.FullName);
        }
    }
    catch (System.Exception ex)
    {
       // We log stuff here
    }

}); 

我不知道为什么你会得到空文件。虽然我怀疑你没有关闭localFile stream.

不过,即使您的代码有效,如果您使用相同的连接进行下载,您也几乎不会获得任何性能优势,因为 SFTP 传输往往会受到网络延迟或 CPU 的限制。您必须使用多个连接来克服这个问题。

See my 关于服务器故障有关影响SFTP传输速度的因素的回答.

实现一些连接池并每次选择一个空闲连接。


简单的例子:

var clients = new ConcurrentBag<SftpClient>();

var opts = new ParallelOptions { MaxDegreeOfParallelism = maxConnections };

Parallel.ForEach(files, opts, (f, loopstate) => {
    if (!clients.TryTake(out var client))
    {
        client = new SftpClient(hostName, userName, password);
        client.Connect();
    }

    string localPath = Path.Combine(destPath, f.Name);
    Console.WriteLine(
        "Thread {0}, Connection {1}, File {2} => {3}",
        Thread.CurrentThread.ManagedThreadId, client.GetHashCode(),
        f.FullName, localPath);

    using (var stream = File.Create(localPath))
    {
        client.DownloadFile(f.FullName, stream);
    }

    clients.Add(client);
});

Console.WriteLine("Closing {0} connections", clients.Count);

foreach (var client in clients)
{
    client.Dispose();
}

另一种方法是启动固定数量的线程,每个线程有一个连接,并让它们从队列中选取文件。

有关实现示例,请参阅我关于 WinSCP .NET 程序集的文章:
通过 SFTP/FTP 协议自动并行连接传输


关于FTP的类似问题:
使用 FluentFTP 以最大值同时从 FTP 下载多个文件

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C# Parallel.ForEach 循环处理 SFTP 文件不处理下载 的相关文章

  • UML类图:抽象方法和属性是这样写的吗?

    当我第一次为一个小型 C 项目创建 uml 类图时 我在属性方面遇到了一些麻烦 最后我只是将属性添加为变量 lt
  • 如何避免情绪低落?

    我有一个实现状态模式每个状态处理从事件队列获取的事件 根据State因此类有一个纯虚方法void handleEvent const Event 事件继承基础Event类 但每个事件都包含其可以是不同类型的数据 例如 int string
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • 如何忽略“有符号和无符号整数表达式之间的比较”?

    谁能告诉我必须使用哪个标志才能使 gcc 忽略 有符号和无符号整数表达式之间的比较 警告消息 gcc Wno sign compare 但你确实应该修复它警告你的比较
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 如何将图像和 POST 数据上传到 Azure 移动服务 ApiController 终结点?

    我正在尝试上传图片and POST表单数据 尽管理想情况下我希望它是json 到我的端点Azure 移动服务应用 我有ApiController method HttpPost Route api upload databaseId sea
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 在 ASP.NET Core 3.1 中使用包含“System.Web.HttpContext”的旧项目

    我们有一些用 Net Framework编写的遗留项目 应该由由ASP NET Core3 1编写的API项目使用 问题是这些遗留项目正在使用 System Web HttpContext 您知道它不再存在于 net core 中 现在我们
  • 在数据库中搜索时忽略空文本框

    此代码能够搜索数据并将其加载到DataGridView基于搜索表单文本框中提供的值 如果我将任何文本框留空 则不会有搜索结果 因为 SQL 查询是用 AND 组合的 如何在搜索 从 SQL 查询或 C 代码 时忽略空文本框 private
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • const、span 和迭代器的问题

    我尝试编写一个按索引迭代容器的迭代器 AIt and a const It两者都允许更改容器的内容 AConst it and a const Const it两者都禁止更改容器的内容 之后 我尝试写一个span
  • ASP.NET MVC 6 (ASP.NET 5) 中的 Application_PreSendRequestHeaders 和 Application_BeginRequest

    如何在 ASP NET 5 MVC6 中使用这些方法 在 MVC5 中 我在 Global asax 中使用了它 现在呢 也许是入门班 protected void Application PreSendRequestHeaders obj
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐

  • `git` 显示克隆后更改的文件,无需任何其他操作

    git clone email protected erocarrera pydot 35a8d858b 在 Debian 中git config core autocrlf input shows modified test graphs
  • 检查是否是用户首次访问

    不知道如何做到这一点 但我想做的是运行一个简单的 jquery 动画 例如 intro eq 0 delay 800 animate opacity 0 1000 function this remove 但仅当用户第一次访问该网站时 因此
  • Jekyll 博客显示类别下的帖子

    我想显示来自某个类别的帖子 例如 转到 urlhttp example com posts programming将列出所有类别为 编程 的帖子 我的一般博客索引如下所示 for post in site posts div class p
  • 如何计算 naive_bayes MultinomialNB 中的 feature_log_prob_

    这是我的代码 Load libraries import numpy as np from sklearn naive bayes import MultinomialNB from sklearn feature extraction t
  • 确定 pandas 数据框中另一列的列最大值

    我有一个数据框 其中包含位置 ID 商店名称和商店收入 我想确定每个区域收入最大的商店 我为此编写了代码 但不确定是否有更好的方法来处理这种情况 import pandas as pd dframe pd DataFrame Loc Id
  • 仅使用 Moment JS 将 Microsoft JSON 日期转换为本地日期时间

    JSON 日期 日期 1373428800000 最终结果 美国东部时间 2013 年 7 月 9 日晚上 8 00 目前我分三步进行 var a cleanJsonDate JsonDate var b formatDate a 7 10
  • 如何根据日期时间生成表名?

    我意识到这在语法上很糟糕 但我认为它在某种程度上解释了我想要做的事情 本质上 我有一个批处理作业 每天早上都会在一个小表上运行 作为规范的一部分 我需要在每次加载之前创建一个可以通过报告访问的备份 到目前为止我所拥有的是 select in
  • 该领域的架构中缺少该类

    项目设置 安卓工作室2 3 3 境界3 5 0 Source RealmController java public RealmController Context context try this context context Real
  • childNodes[] 在 IE9 中无法像在 IE7 和 8 中一样工作

    我有一些代码可以在 IE7 和 8 中运行 但不能在 9 中运行 var table document getElementById RadGrid ctl01 childNodes 2 这在 IE9 中不起作用 现在我确实读到 IE9 计
  • 如何使用 Twisted 获取 IRC 频道的用户列表

    我正在尝试使用获取频道的用户列表 self say channel WHO 100 我怎样才能得到回复 我应该重写哪个方法 这里有一些额外的方法可以帮助您取得进一步的进展 您处理给定的回复RPL NAME通过定义一个方法irc RPL NA
  • 如何使用Maven只签署三个jar并将它们推送到Maven Central?

    更新 参见跟进问题 我有一个 Java 库 其构建过程完全用 Ant 编写 项目的沙箱 源目录 我在其中编辑代码 是 R jeffy programming sandbox xbnjava 它的构建 输出 目录是 R jeffy progr
  • 如何使用 PHP 将撇号从文本区域传递到 MySQL

    我有一个文本区域 用户也可以添加注释 在下一页上我使用 POST Comments 显示输入的内容 我有一个编辑按钮可以返回并查看输入的内容并编辑注释 但是当我显示 POST Comments 它显示了撇号之前的所有内容 Example 最
  • 使用 $.ajax 时成功后访问 $(this):function()

    使用 jquery 时 如何在 success function 后访问 this 的值 无论我尝试什么 似乎我都做不到 add click function etc etc ajax type GET url data data data
  • C# 库做 fft 和 ifft? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 是否有免费的 C 库可以进行快速傅立叶变换及其逆变换 Math NET 和 Aforce 都基于 Exocortex DSP 库 http www
  • Hiredis 等待消息

    我正在使用hiredis C 库连接到redis 服务器 我无法弄清楚如何在订阅新消息后等待新消息 我的代码如下所示 signal SIGPIPE SIG IGN struct event base base event base new
  • Qt:MouseMove 无法运行

    在我的 Qt 应用程序中 我需要跟踪鼠标移动 为此 我创建了一个eventfilter我正确安装了它 如下所示 bool iArmMainWindow eventFilter QObject obj QEvent event if even
  • 为什么 Node.js 将传入数据分成块?

    Node js 中的以下代码不会将所有传入数据记录在括号内 而是将数据分成块 例如 如果传入数据是 ABCDEF XYZ 它将数据记录为 ABC DEF XYZ 而不是 ABCDEF XYZ 当然数据要大得多 字母表只是一个例子 我应该如何
  • 为什么Java I/O中的一个字节可以代表一个字符?

    为什么Java I O中的一个字节可以代表一个字符 我看到这些字符只是 ASCII 那么它就不是动态的了 对吧 对此有什么解释吗 字节流和字符流有什么区别 字节不是字符 独自一人 他们甚至无法代表人物 从计算角度来说 字符 是数字代码 或代
  • 将可执行文件链接到的所有 dll 复制到可执行目录

    这个问题询问类似的问题 但只需要手动指定要复制的dll 我的问题是 有没有一种方法可以简单地让 CMake 复制链接到可执行库的所有 dll 而不需要手动告诉 CMake 要复制哪些文件 有时 CMake 更了解是否需要 dll 例如 在安
  • 使用 C# Parallel.ForEach 循环处理 SFTP 文件不处理下载

    我正在使用 Renci SSH NET 软件包版本 2016 我正在从外部服务器下载文件 我通常每 6 秒就能下载一个文件 当你有数千个文件时 这很糟糕 我最近尝试改变foreach循环到Parallel ForEach 这样做将文件下载时