Сборка C# WinSCP .NET: как асинхронно загрузить несколько файлов

Я использую сборку WinSCP .NET для загрузки файлов. Я хочу загрузить несколько файлов асинхронным способом. Я создал метод, но он работает как одиночная загрузка.

public class UploadingData {

    private SessionOptions _sessionOptions;
    private Session _session;

    //connection etc

    private void OnConnected() {

        foreach (var fileInfo in localFilesList)
        {
            var task = Task.Factory.StartNew(() => UploadFilesAsync(fileInfo));
        }
    }

    private async Task UploadFilesAsync(string file) {

        string remoteFilePath = _session.TranslateLocalPathToRemote(file, @"/", "/test_data_upload");
        var uploading = _session.PutFiles(file, remoteFilePath, false);

        //When Done

        await Task.Run(() => Thread.Sleep(1000));
    }
}

Пожалуйста, предложите мне правильный путь. Спасибо


person Shoaib Ijaz    schedule 10.11.2016    source источник


Ответы (2)


API класса Session можно использовать только из одного потока. Если вы используете его из нескольких потоков, он будет заблокирован.

Поэтому, если вам нужны параллельные передачи, вам нужно создать отдельный экземпляр Session для каждого потока.

private async Task UploadFilesAsync(string file)
{
    using (Session session = new Session())
    {
        session.Open(_sessionOptions);
        string remoteFilePath =
            RemotePath.TranslateLocalPathToRemote(file, @"/", "/test_data_upload");
        session.PutFiles(file, remoteFilePath, false).Check();
    }

    ...
}

См. также статью WinSCP Автоматизация передачи в параллельных соединениях по протоколу SFTP/FTP с примерами кода для C# и PowerShell.

Обратите внимание, что вы не должны использовать более нескольких сеансов/потоков (около 4). С большим количеством сеансов вы вряд ли улучшите пропускную способность.

person Martin Prikryl    schedule 10.11.2016

Вы можете использовать класс BackgroundWorker следующим образом:

        string[] images = new string[50];
        foreach (var path in images)
        {
            BackgroundWorker w = new BackgroundWorker();
            //50 independently async Threads
            w.DoWork += delegate (object s, DoWorkEventArgs args) 
            {
                Upload(args.Argument.ToString());
            };
            w.RunWorkerAsync(path);
        }
person Tamerlan Rustambayli    schedule 10.11.2016
comment
Если мне нужно загрузить тысячи файлов, тогда будут тысячи фоновых рабочих. это нормально для приложения и процессора? - person Shoaib Ijaz; 10.11.2016
comment
Использование тысяч объявлений в одном приложении не является хорошей практикой. Таким образом, чем больше в вашем приложении потоков, тем меньше квота времени на выполнение каждого потока. Вы можете разделить тысячи файлов на 50-50 и загружать каждую часть последовательно, например, с помощью 50 асинхронных потоков. - person Tamerlan Rustambayli; 10.11.2016
comment
Как сказал @Martin, класс Session поставит все файлы в очередь. - person Shoaib Ijaz; 10.11.2016