C# 限制并发异步任务

C# 限制并发异步任务,c#,async-await,semaphore,C#,Async Await,Semaphore,我想使用SSH.NET库和扩展名将可能大批量(可能是100个)的文件上传到FTP。我需要将并发上传的数量限制在5个,或者我发现FTP可以处理的任何数量 这是我在任何限制之前的代码: using (var sftp = new SftpClient(sftpHost, 22, sftpUser, sftpPass)) { var tasks = new List<Task>(); try { sftp.Connect(); fo

我想使用
SSH.NET
库和扩展名将可能大批量(可能是100个)的文件上传到FTP。我需要将并发上传的数量限制在5个,或者我发现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
}
据我所知,Task.Run用于CPU限制的工作

异步/等待I/O绑定工作

否。
await
是一种用于向异步操作添加连续性的工具。它不关心异步操作的性质。它只是使将任何类型的异步操作组合在一起变得更容易

如果要将多个异步操作组合在一起,可以使用各种异步操作创建一个
async
方法,
在需要它们的结果时等待它们(或等待它们完成),然后使用
任务将该方法作为其自己的新异步操作

在您的情况下,新的异步操作只需要等待信号量,上载文件,然后释放信号量

async Task UploadFile()
{
    await semaphore.WaitAsync();
    try
    {
        await sftp.UploadAsync(
            File.OpenRead(file),
            Path.GetFileName(file),
            true));   
    }
    finally
    {
        semaphore.Release();
    }
}
现在,您可以简单地为每个文件调用该方法


此外,由于这是一个非常常见的操作,您可能会发现它是值得的,因此您可以简单地创建一个队列,并向队列中添加项目,让它在内部处理节流,而不是在您使用它的任何地方复制该机制。

您查看过线程池吗?特别是问题中提到的@DotNetPadawan,这不是CPU限制的工作。它不会将线程池用于实际的长时间运行操作。可能重复
async Task UploadFile()
{
    await semaphore.WaitAsync();
    try
    {
        await sftp.UploadAsync(
            File.OpenRead(file),
            Path.GetFileName(file),
            true));   
    }
    finally
    {
        semaphore.Release();
    }
}