2015-04-03 3 views
0

Я экспериментировал с каким-то старым кодом, который нуждается в рефакторинге в местах и ​​тестировал, было ли какое-либо улучшение для потоков iis и т. Д., Загружая файл асинхронно (на стороне сервера). Использование клиентской части загрузки файла jQuery.Использование async & await .net 4.5 mvc C#

Исходный код

[HttpPost] 
public ActionResult UploadDocument(HttpPostedFileBase uploadedFile) { 

    // Do any validation here 

    // Read bytes from http input stream into fileData 
    Byte[] fileData; 

    using (BinaryReader binaryReader = 
      new BinaryReader(uploadedFile.InputStream)) { 

    fileData = binaryReader.ReadBytes(uploadedFile.ContentLength); 

    } 

    // Create a new Postgres bytea File Blob ** NOT Async ** 
    _fileService.CreateFile(fileData); 

    return Json(
    new { 
     ReturnStatus = "SUCCESS" // Or whatever 
    } 
); 

} 

Новый код

[HttpPost] 
public async Task<ActionResult> UploadDocumentAsync(HttpPostedFileBase uploadedFile) { 

    // Do any validation here 

    // Read bytes from http input stream into fileData 
    Byte[] fileData = new Byte[uploadedFile.ContentLength]; 

    await uploadedFile.InputStream.ReadAsync(fileData, 0, uploadedFile.ContentLength); 

    // Create a new Postgres bytea File Blob ** NOT Async ** 
    _fileService.CreateFile(fileData); 

    return Json(
    new { 
     ReturnStatus = "SUCCESS" // Or whatever 
    } 
); 

} 

Новый метод, как представляется, правильно работать, но мой вопрос:

Является ли следующий код правильный (лучший) способ сделать это? и есть ли какие-либо попытки сделать это таким образом? Существует много противоречивой и устаревшей информации. Там также, кажется, много споров о том, есть ли какие-либо улучшения или на самом деле это делается. Да, он возвращает потоки в iis и т. Д., Но стоит ли обсуждать накладные вопросы.

Код в вопросе

// Read bytes from http input stream into fileData 
Byte[] fileData = new Byte[uploadedFile.ContentLength]; 

await uploadedFile.InputStream.ReadAsync(fileData, 0, uploadedFile.ContentLength); 
+2

Асинхронный/ждущий хвост виляет собакой, я думаю. Хотелось бы увидеть некоторые аргументы, которые докажут, что я ошибаюсь. Это хороший вопрос. Поэтому почти наверняка будет удален какой-то администратор скремблирования. – Sam

+0

Почему вы не создали async CreateFile? Это тестовый вопрос, чтобы узнать, есть ли у вас определенное общее недоразумение или нет. Тем временем я хотел бы сослаться на ваше обращение к этой теме: http://stackoverflow.com/a/25087273/122718 и http://stackoverflow.com/a/12796711/122718. – usr

+0

usr Я, вероятно, буду, но это не то, что я просил. Хотя по этой теме много дискуссий о том, быстрее ли синхронизирован быстрый доступ к локальной базе данных. –

ответ

1

Код корректен. Использование async IO - это не все или ничего. Вы можете смело смешивать синхронизацию и асинхронный ввод-вывод, как вы это делали.

Whether you should be using async has been covered already. Для ASP.NET основным правилом является использование его в тех случаях, когда операция может иметь очень высокую задержку и в то же время вызывается много. Только в этом случае важно не освобождать потоки. Если операции бывают быстрыми или редкими, то свободных потоков нет, и это пустая трата времени разработчика.

Чтение из буферизованного (по умолчанию) входного потока совпадает с чтением из файла. ASP.NET поддерживает длительные входы в файлы на диске. Это классический случай, когда async IO не обеспечивает прирост пропускной способности. В скором времени файл, скорее всего, будет полностью кэширован, так что IO будет чисто основан на процессоре (memcpy из кэша). Общая потеря времени разработки и циклов процессора. Никаких преимуществ.

+0

Итак, в этом случае вы сказали бы, что это хорошая вещь для Async загрузки файлов или нет. –

+0

Мой совет: поскольку у вас, вероятно, очень мало одновременных загрузок, вопрос спорный. Используйте синхронный по умолчанию. Если вы действительно хотите, чтобы это было асинхронным, сделайте загрузку небуферизованной. Это где-то в ASP.NET. – usr

+0

Это довольно непонятная тема и много противоречивой информации. Это не значит, что теперь он стал «модным», чтобы сделать это способом Async. –

-2

Для всех проблем вы ставите в асинхронном ждать, вы можете быть в состоянии сделать что-то вроде этого:

try 
{ 
    Task.Run(() => uploadedFile.InputStream.Read(fileData, 0, uploadedFile.ContentLength)); 
} 
catch() 
{ 
    // etc. 
} 

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

Кстати, вы можете, вероятно, добавить намного больше кода в эту задачу, включая вызовы на ваш db. Я просто опубликовал это как пример.

EDIT ..... За комментариями, приведенными ниже, мой ответ заключается в том, что во многих случаях лошадиная сила может быть направлена ​​и использоваться с гораздо большим предсказуем с задачами против async/await. Это не шок от асинхронного ожидания, просто вопрос использования правильного инструмента для работы. Вот пример кода с сервера производства, что делает именно то, что:

 Task t1 = Task.Run(() => GetBusinessProcesses(-1)); 
     Task t2 = Task.Run(() => GetActivityRoles(-1)); 
     Task t3 = Task.Run(() => Tools = toolService.GetTools().ToSelectListItem(x => x.Name, x => x.ToolId.ToString(), true).ToList()); 
     Task t4 = Task.Run(() => BusinessAreas = businessAreaService.GetBusinessAreas().ToSelectListItem(x => x.Name, x => x.BusinessAreaId.ToString(), true).ToList()) 
      .ContinueWith(t => 
     { 
      // Populate the functional area dropdown data 
      if (BusinessAreas != null && BusinessAreas.Any()) 
      { 
       int businessAreaId = System.Convert.ToInt32(BusinessAreas[0].Value); 
       GetFunctionalAreas(businessAreaId); 
      } 
     }); 

     try 
     { 
      Task.WaitAll(t1, t2, t3, t4); 
     } 
     catch (Exception ex) 
     { 
      throw new Exception("Error populating dropdowns. See inner exception.", ex); 
     } 

В коде выше я делаю четыре параллельных вызовов на мою БД и построить четыре списка параллельно. Я жду задач и верну страницу.В случае с ФП, он может сделать:

Task t1 = Task.Run(() => parse the file).ContinueWith(x => write to the db); 
    Task t2 = Task.Run(() => more work); 
    // do some work here 
    Task.WaitAll(t1, t2); 
    // Return the page 
+0

Это кажется немного переполненным, и я думаю (хотя я мог ошибаться) именно поэтому MS создала новый способ сделать это. Приложение, на котором работает мой код, на самом деле не будет функционировать правильно, если загрузка не будет «блокироваться», так сказать, пока он не завершится. Реальный выигрыш дебатирует - это освобождение потоков от IIS для обслуживания страниц, а не их использование для длительной загрузки файлов. Это не значит, что он работает по-настоящему параллельно. Если это действительно так, мне нужен такой параллелизм, я бы смотрел на конец erlang, а не на .net, хотя это еще одна дискуссия. –

+2

Это заставляет работать огонь и забывать, что, вероятно, нежелательно. Кроме того, это нарушается в том смысле, что это будет использовать объекты запроса после завершения запроса. Он также использует их одновременно, что очень полезно. – usr

+0

После всех обручей вам нужно перепрыгнуть, чтобы использовать async wait. Мне остается не думать, как код, который я написал, можно назвать overkill. В любом случае, мой ответ заключается в том, что async/await часто не направляет лошадиную силу на ваш ресурс в наиболее нужные вам места. Имейте в виду, что async/await не является заменой или заменой для параллелизма. Это не новый способ сделать это. Кроме того, IIS не знает и не заботится о выполнении фоновой задачи. Ваша страница все равно возвращается. Если это не подходит для вашего приложения, не так оно и есть. Надеюсь, по крайней мере, я предложил вам несколько вариантов для изучения. С уважением, – Sam

1

Чтобы ответить на ваши вопросы конкретно:

  1. Там нет ничего плохого с кодом, и, на мой взгляд, вы должны идти вперед с этим изменением. В зависимости от множества факторов (размер файлов/буферизация, как указано, параллелизм и т. Д.), Это может или не может заметно улучшить (и любое улучшение будет в масштабируемости, а не в скорости), но вы почти наверняка не будете хуже выключено. «Накладные расходы», о которых вы говорите, включает в себя конечный автомат, написанный компилятором, и в большинстве случаев это nearly negligable.

  2. Одна небольшая Гоча я могу думать о: Вы хотели бы взглянуть на то, что происходит послеawait и убедитесь, что нет никаких предположений, что этот код будет работать на том же потоке, что и код перед await , Скорее всего, в этом случае, но что-то, о чем нужно знать.

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

Относительно длительный ввод-вывод является обычным явлением в серверных приложениях (работает с файлами, вызывает внешние API-интерфейсы и т. Д.), А освобождение потоков для выполнения других работ во время этих операций почти всегда является преимуществом.

+0

Да, я согласен с другим хорошим ответом. –

Смежные вопросы