我想使用SSH.NET
库和Renci.SshNet.Async
扩展名将潜在的大批文件(可能是100个)上传到FTP。我需要将并发上传的数量限制为五个,或者我发现FTP可以处理的任何数量。
这是我的代码,没有任何限制:
using (var sftp = new SftpClient(sftpHost, 22, sftpUser, sftpPass))
{
var tasks = new List<Task>();
try
{
sftp.Connect();
foreach (var file in Directory.EnumerateFiles(localPath, "*.xml"))
{
tasks.Add(
sftp.UploadAsync(
File.OpenRead(file), // Stream input
Path.GetFileName(file), // string path
true)); // bool canOverride
}
await Task.WhenAll(tasks);
sftp.Disconnect();
}
// trimmed catch
}
我已经读过SemaphoreSlim
,但是我不完全了解它是如何工作的以及如何与TAP一起使用。这是基于MSDN documentation的实现方式。
我不确定使用Task.Run
是否是正确的方法,因为它受I / O限制,据我所知,Task.Run
是用于CPU约束的工作,而{{ 1}} / async
用于I / O绑定工作。我也不理解这些任务如何进入信号量(是正确的术语)信号量,因为它们所做的只是在其上调用await
。
.Release()
答案 0 :(得分:1)
据我所知,Task.Run用于CPU绑定工作
正确。
并异步/等待绑定到I / O的工作。
不。 await
是用于将延续添加到异步操作的工具。 它不在乎异步操作是什么性质。它简单地使组合任何类型的异步操作 更加容易。
如果您想将几个异步操作组合在一起,则可以通过使用各种异步操作制作async
方法,在需要它们的结果(或完成它们)时await
对其进行编排。 ),然后使用Task
形式的方法作为其自己的新异步操作。
在您的情况下,您的新异步操作只需要等待信号量,上传文件然后释放信号量即可。
async Task UploadFile()
{
await semaphore.WaitAsync();
try
{
await sftp.UploadAsync(
File.OpenRead(file),
Path.GetFileName(file),
true));
}
finally
{
semaphore.Release();
}
}
现在,您只需为每个文件调用该方法即可。
另外,由于这是常见的操作,因此您可能会发现create a new class to handle this logic值得这样做,这样您就可以简单地创建一个队列并将项目添加到该队列中,并让它在内部处理节流,而不是在您使用它的任何地方复制该机制。