Потоки лучших практик при использовании SFTP в C # - PullRequest
4 голосов
/ 13 апреля 2010

Хорошо,

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

  • Я хочу запросить у SFTP-сервера список каталогов и файлов
  • Я хочу загружать или скачивать файлы одновременно

Обе вещи довольно просты с использованием класса SFTP, предоставленного Tamir.SharpSsh, но если я использую только один поток, это будет довольно медленно. Особенно рекурсия в подкаталоги получает очень «блокировку пользовательского интерфейса», потому что мы говорим о 10.000 каталогов.

Мой основной подход прост: создать некий «пул», в котором я сохраняю 10 открытых SFTP-соединений. Затем запросите у первого работника список директоров. Если этот список был получен, отправьте следующих свободных работников (например, 1-10, первый также снова свободен), чтобы получить детали подкаталога. Как только освободится рабочий, отправьте его за субподрядчиками. И так далее ...

Я знаю ThreadPool, простые Threads и провел несколько тестов. Что меня немного смущает, так это то, что мне нужно ...

  • Список созданных мной тем, скажем, 10
  • Подключить все темы к серверу
  • Если соединение разорвано, создайте новый поток / клиент sftp
  • Если есть над чем поработать, возьмите первую свободную ветку и выполняйте работу

В настоящее время я не уверен в деталях реализации, особенно в части «работа над выполнением» и «ведение списка потоков».

Это хорошая идея:

  • Заключить работу в объект, содержащий описание задания (путь) и обратный вызов
  • Отправка потоков в бесконечный цикл с ожиданием 100 мс в ожидании работы
  • Если SFTP мертв, либо возродить его, либо уничтожить весь поток и создать новый
  • Как инкапсулировать это, написать свой собственный "10ThreadsManager" или есть какие-то

Хорошо, пока ...

Кстати, я мог бы также использовать PRISM-события и команды, но я думаю, что проблема не связана. Возможно EventModel, чтобы сигнализировать законченную обработку "рабочего пакета" ...

Спасибо за любые идеи, критик .. Chris

Ответы [ 3 ]

2 голосов
/ 13 апреля 2010

Куча мелких нот:

Если вы используете некоторый .NET API, который внутренне использует ThreadPool, то вы не можете делать бесконечное ожидание, поскольку ОС владеет потоками из ThreadPool, эти потоки предназначены для «краткого» использования, а затем возвращаются обратно в ОС. Это самое надежное поведение. Несомненно, операционная система может увеличивать пул потоков по мере необходимости, если вы в конечном итоге включите их из-за длительной обработки, но лучше было бы избежать такого поведения.

Если вы работаете в XP, вы также можете избегать ThreadPool (уровень ОС и, следовательно, .NET), поскольку он был исправлен / оставлен в Windows Vista и более поздних версиях, версия XP считается менее надежной.

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

Создать собственный ThreadManager довольно просто, вы можете найти множество примеров по этому поводу, но, как всегда, подобные вещи должны быть максимально простыми.

Что касается третьего пункта, лучше восстановить SFTP-соединение, чем уничтожить весь поток. Если вы завершаете работу потока (при условии, что ваш ThreadManager может с этим справиться, конечно же, никогда не уничтожайте потоки из ОС ThreadPool), то сначала ему придется вернуть необработанное задание обратно в какую-то очередь, что кажется слишком большой работой.

0 голосов
/ 28 июля 2016

для использования SFTP и .NET с tamir.ssh и multithead вы можете сделать это следующим образом:

  • Создайте основной экземпляр, который запустит поток, который.

Task.Factory.StartNew (() => new Main (). Run ());

  • 1.1 Загрузка файлов с SFT

  • 1.2 Загрузка файлов из SFTP

ГЛАВНЫЙ класс

публичный класс Main { Task [] _tasks = null;

   public void run()
    {
       _tasks = new Task[2]; 

      var task = new Task(() => Download(),TaskCreationOptions.LongRunning);
                task.Start();
                _tasks[0] = task;
      var task = new Task(() => Download(),TaskCreationOptions.LongRunning);
                task.Start();
                _tasks[1] = task;

      Task.WaitAny(_tasks); 
    }

   private void Upload()
   {  Sftp _Sftp = null;
      while (true)
      {
        filesToUpload = GetFiles(Sourcepath);

           Parallel.ForEach(filesToUpload, _fileData =>
           { 
               if(!_Sftp.Insconnected)
                  {
                   _Sftp = new Sftp(Host, User,Password);
                     _Sftp.Connect();
                  }

                if(_Sftp.Connected)
                  _Sftp.Put(_fileData.Path, DestinyPath);
           });         

      }

   }

   public void Download()
    {
         Sftp _Sftp = null; 
        While(true)
        {
           if(!_Sftp.Connected)
                  {
                   _Sftp = new Sftp(Host, User,Password);
                     _Sftp.Connect();
                   }

                if(_Sftp.Connected)

{

ArrayList fileToDownload = _Sftp.GetFileList (_Instance.Sourcepath);

 Parallel.ForEach(fileToDownload, _fileData =>
      {
        _Sftp.Get(Sourcepath + "/" + _fileData.Name,DestinyPath);
      });    
       }       

    }

} 
0 голосов
/ 13 апреля 2010

Альтернативный подход заключается в рассмотрении использования FtpDlx от WeOnlyDo (http://www.weonlydo.com/FtpDLX.NET/ftp.sftp.ftps.ssl.net.component.asp). Это всего $ 229 и полностью управляемая библиотека .Net 2.0. Она включает методы для рекурсивной загрузки каталога. Она использует события для индикации прогресса и ошибок. , позволяя пропускать файлы, перенаправлять туда, куда вы их записываете, а также проверять и игнорировать ошибки. Он надежен и работает так, как объявлено; мы используем его в многопоточном производственном коде.

Вы можете запустить его в отдельном потоке и использовать события для обновления вашего интерфейса без блокировки. Вы даже можете обнаружить, что один поток, выполняющий загрузку, эффективно использует вашу пропускную способность, но он будет работать нормально с отдельными соединениями в отдельных потоках. Я бы порекомендовал вам создавать свои собственные потоки вместо использования ThreadPool, так как вы захотите использовать обратные вызовы, и потоки в любом случае будут иметь длительный характер.

...