Ограничение одновременных асинхронных задач - PullRequest
0 голосов
/ 21 марта 2019

Я хочу загрузить потенциально большие партии (возможно, 100 с) файлов на FTP, используя библиотеку SSH.NET и расширения Renci.SshNet.Async. Мне нужно ограничить число одновременных загрузок пятью или любым количеством, которое, как я обнаружил, может обработать 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 , я бы это реализовал.

Я не уверен, правильно ли использовать Task.Run для этого, так как он связан с вводом / выводом, и, насколько я знаю, Task.Run для работы с процессором и async / await для работы с вводом / выводом. Я также не понимаю, как эти задачи входят (это правильная терминология) в семафор, так как все, что они делают, это вызывают на нем .Release().

using (var sftp = new SftpClient(sftpHost, 22, sftpUser, sftpPass))
{
    var tasks = new List<Task>();
    var semaphore = new SemaphoreSlim(5);
    try
    {
        sftp.Connect();

        foreach (var file in Directory.EnumerateFiles(localPath, "*.xml"))
        {
            tasks.Add(
                Task.Run(() =>
                {
                    sftp.UploadAsync(
                        File.OpenRead(file),      // Stream input
                        Path.GetFileName(file),   // string path
                        true));                   // bool canOverride
                    semaphore.Release();
                });
        }

        await Task.WhenAll(tasks);
        sftp.Disconnect();
    }
    // trimmed catch
}

1 Ответ

1 голос
/ 22 марта 2019

Из того, что я знаю, Task.Run предназначен для работы с процессором

Исправить.

и async / await для ввода-выводаработа.

Нет.await - это инструмент для добавления продолжений в асинхронную операцию. Его не волнует характер этой асинхронной операции .Это просто облегчает составление асинхронных операций любого вида .

Если вы хотите составить несколько асинхронных операций вместе, вы делаете это, делая метод async, используя различные асинхронные операции.операции await, когда вам нужны их результаты (или для их завершения), а затем используйте метод формы Task в качестве собственной новой асинхронной операции.

В вашем случае ваша новая асинхронная операцияпросто нужно дождаться семафора, загрузить файл, а затем выпустить семафор.

async Task UploadFile()
{
    await semaphore.WaitAsync();
    try
    {
        await sftp.UploadAsync(
            File.OpenRead(file),
            Path.GetFileName(file),
            true));   
    }
    finally
    {
        semaphore.Release();
    }
}

Теперь вы можете просто вызвать этот метод для каждого файла.

Дополнительно, потому что это такие обычная операция, которую вы можете сделать, вы можете создать новый класс для обработки этой логики , чтобы вы могли просто создать очередь, добавить элементы в очередь и получитьон обрабатывает внутреннее регулирование, а не копирует механику везде, где вы ее используете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...