Загрузка файлов в хранилище больших двоичных объектов Azure — параллельная.Foreach медленнее, чем Foreach

#azure #azure-storage #task-parallel-library #azure-blob-storage #parallel.foreach

#azure #azure-хранилище #задача-параллельная-библиотека #azure-blob-storage #parallel.foreach

Вопрос:

У меня есть следующий код для загрузки папки из локального хранилища в хранилище больших двоичных объектов, включая само имя папки в имени большого двоичного объекта (код основан на некоторых методах, найденных здесь http://blog.smarx.com/posts/pivot-odata-and-windows-azure-visual-netflix-browsing ) :

 public static void UploadBlobDir(CloudBlobContainer container, string dirPath)
        {
            string dirName = new Uri(dirPath).Segments.Last();

            Parallel.ForEach(enumerateDirectoryRecursive(dirPath), file =>
                {
                    string blobName = Path.Combine(dirName, Path.GetFullPath(file)).Substring(dirPath.Length - dirName.Length);
                    container.GetBlobReference(blobName).UploadFile(file);
                });
        }
  

и :

 private static IEnumerable<string> enumerateDirectoryRecursive(string root)
        {
            foreach (var file in Directory.GetFiles(root))
                yield return file;
            foreach (var subdir in Directory.GetDirectories(root))
                foreach (var file in enumerateDirectoryRecursive(subdir))
                    yield return file;
        }
  

Этот код работает и загружает папку по назначению, но для его завершения требуется очень много времени — для загрузки 25 файлов по 40 КБ ~ каждый требуется 20 секунд. Итак, я устал заменять параллельный цикл обычным, например :

 foreach (var file in enumerateDirectoryRecursive(i_DirPath))
            {
                string blobName = Path.Combine(dirName, Path.GetFullPath(file)).Substring(i_DirPath.Length - dirName.Length);
                container.GetBlobReference(blobName).UploadFile(file);
            }
  

Теперь загрузка завершается мгновенно (примерно за 3 секунды).

Также важно отметить, что я работаю с эмулятором хранилища для разработки.
Параллель.Очевидно, что Forech должен быть быстрее. Возникает ли эта разница из-за ограничений эмулятора хранилища (и при запуске в режиме реального времени Parallel будет быстрее) или это что-то еще, что я могу делать неправильно?

Ответ №1:

По моему опыту, эмулятор хранилища ничего не сообщает вам о производительности, которую вы должны ожидать (или нет) от фактического хранилища Azure. Эмулятор обычно работает очень медленно.

Тогда Parallel.Foreach будет быстрее, только если ваша передача связана с задержкой, а не с вводом-выводом. Тогда, пожалуйста, обратите внимание, что Parallel.Foreach в качестве степени распараллеливания по умолчанию будет использоваться только ваше количество процессоров. Для процессов, связанных с задержкой, у вас обычно должно быть намного больше потоков, обычно от 4 до 8 потоков на процессор (YMMV).

Комментарии:

1. Можете ли вы более подробно объяснить, что вы подразумеваете под привязкой ввода-вывода и задержкой, и к какому регистру относится мой код? (Просто напоминаю, я загружаю из локального хранилища, если это имеет значение)

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

3. @OliverBock Вы можете быть более конкретными? Вы имеете в виду параллельное использование. Foreach и внутри него вызывают какой асинхронный API?

4. @YaronLevi, вызовите CloudBlob . BeginUploadFromStream() в обычном цикле for . Он позаботится о запуске и выполнении загрузки асинхронно и перезвонит вам (из другого потока) по завершении.