gpt4 book ai didi

c# - 具有多个创建 FTP 请求的线程的 ThreadPool 超时

转载 作者:行者123 更新时间:2023-11-30 12:16:58 24 4
gpt4 key购买 nike

我正在尝试创建一组 FTP 网络请求以下载一组文件。

在单个线程中正确执行此操作,但我现在尝试使用多个线程执行此操作,但出现超时异常。我想我遗漏了一些非常简单但似乎无法解决的问题

代码如下:

internal static void DownloadLogFiles(IEnumerable<string> ftpFileNames, string localLogsFolder)
{
BotFinder.DeleteAllFilesFromDirectory(localLogsFolder);

var ftpWebRequests = new Collection<FtpWebRequest>();

// Create web request for each log filename
foreach (var ftpWebRequest in ftpFileNames.Select(filename => (FtpWebRequest) WebRequest.Create(filename)))
{
ftpWebRequest.Credentials = new NetworkCredential(BotFinderSettings.FtpUserId, BotFinderSettings.FtpPassword);
ftpWebRequest.KeepAlive = false;
ftpWebRequest.UseBinary = true;
ftpWebRequest.CachePolicy = NoCachePolicy;
ftpWebRequest.Method = WebRequestMethods.Ftp.DownloadFile;
ftpWebRequests.Add(ftpWebRequest);
}

var threadDoneEvents = new ManualResetEvent[ftpWebRequests.Count];

for (var x = 0; x < ftpWebRequests.Count; x++)
{
var ftpWebRequest = ftpWebRequests[x];
threadDoneEvents[x] = new ManualResetEvent(false);
var threadedFtpDownloader = new ThreadedFtpDownloader(ftpWebRequest, threadDoneEvents[x]);
ThreadPool.QueueUserWorkItem(threadedFtpDownloader.PerformFtpRequest, localLogsFolder);
}

WaitHandle.WaitAll(threadDoneEvents);
}

class ThreadedFtpDownloader
{
private ManualResetEvent threadDoneEvent;
private readonly FtpWebRequest ftpWebRequest;

/// <summary>
///
/// </summary>
public ThreadedFtpDownloader(FtpWebRequest ftpWebRequest, ManualResetEvent threadDoneEvent)
{
this.threadDoneEvent = threadDoneEvent;
this.ftpWebRequest = ftpWebRequest;
}

/// <summary>
///
/// </summary>
/// <param name="localLogsFolder">
///
/// </param>
internal void PerformFtpRequest(object localLogsFolder)
{
try
{
// TIMEOUT IS HAPPENING ON LINE BELOW
using (var response = ftpWebRequest.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
const int length = 1024*10;
var buffer = new Byte[length];
var bytesRead = responseStream.Read(buffer, 0, length);

var logFileToCreate = string.Format("{0}{1}{2}", localLogsFolder,
ftpWebRequest.RequestUri.Segments[3].Replace("/", "-"),
ftpWebRequest.RequestUri.Segments[4]);

using (var writeStream = new FileStream(logFileToCreate, FileMode.OpenOrCreate))
{
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, length);
}
}
}
}

threadDoneEvent.Set();
}
catch (Exception exception)
{
BotFinder.HandleExceptionAndExit(exception);
}
}
}

它似乎正在下载前两个文件(我假设使用两个线程)但是当这些文件完成并且应用程序尝试移动到下一个文件时似乎会发生超时。

我可以确认超时的 FTPWebRequest 有效并且文件存在,我想我可能有一个打开的连接或其他东西。


本来打算发表评论,但可能更容易在答案中阅读:

首先,如果我将 ftpRequest.Timout 属性设置为 Timeout.Infinite,超时问题就会消失,但是无限超时可能不是最佳实践。所以我宁愿用另一种方式解决这个问题......

调试代码,我可以看到:

ThreadPool.QueueUserWorkItem(threadedFtpDownloader.PerformFtpRequest, localLogsFolder);

它为每个 FTP Web 请求进入 PerformFtpRequest 方法并调用 ftpWebRequest.GetResponse() 但随后仅对前两个请求进行进一步处理。其余请求保持事件状态,但在前两个请求完成之前不会再继续。所以这基本上意味着它们在等待其他请求完成之前保持打开状态。

我认为这个问题的解决方案是允许所有请求同时执行(ConnectionLimit 属性在这里没有效果)或者阻止执行调用 GetResponse 直到它真正准备好使用响应。

关于解决此问题的最佳方法有什么好的想法吗?目前我能想到的似乎都是我想避免的骇人听闻的解决方案:)

谢谢!

最佳答案

您应该获取请求的 ServicePoint 并设置 ConnectionLimit

ServicePoint sp = ftpRequest.ServicePoint;
sp.ConnectionLimit = 10;

默认的 ConnectionLimit 是 2——这就是您看到该行为的原因。

更新:请参阅此答案以获得更详尽的解释:

How to improve the Performance of FtpWebRequest?

关于c# - 具有多个创建 FTP 请求的线程的 ThreadPool 超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4424576/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com