none
ASP.NET MVC. Как сделать блокировку для параллельных запросов? RRS feed

  • Вопрос

  • Для ASP.Net MVC.

    При обращении к экшену GetImageThumbnail возвращается уменьшенная копия исходного изображения. Копия берется из кэша (специальный каталог в файловой системе). Если там ее нет, то она создается и помещается в кэш. Метод CreateImageThumbnail, который создает копию, требует существенного машинного времени. Во время создания копии могут быть получены другие запросы на возвращение уменьшенной копии. Это приводит к переполнению или конфликту доступа (и вообще не корректно).

    Какие существуют варианты решения данной задачи? Как сделать блокировку, чтобы повторные запросы не начинали тоже генерировать копию, а ждали, пока закончится генерация первой копии?

    public ActionResult GetImageThumbnail(string originalPath)
    {
      string copyPath = originalPath + ".th.jpg";
      if (!System.IO.File.Exists(copyPath))
        CreateImageThumbnail(originalPath, copyPath);
      return File(copyPath, "image/jpeg");
    }
    
    public void CreateImageThumbnail(string originalPath, string copyPath)
    {
      // Generate and save thumbnail jpeg
    }
    

     

    27 апреля 2014 г. 19:03

Ответы

  • Вызывайте метод в блокировке.

    using System.Web.Mvc;
    
    namespace MvcApplication.Controllers
    {
        public class DefaultController : Controller
        {
            private static readonly object lockObject = new object();
    
            public ActionResult GetImageThumbnail(string originalPath)
            {
                string copyPath = originalPath + ".th.jpg";
                if (!System.IO.File.Exists(copyPath))
                {
                    lock (lockObject)
                    {
                        if (!System.IO.File.Exists(copyPath))
                        {
                            CreateImageThumbnail(originalPath, copyPath);
                        }
                    }   
                }
    
                return this.File(copyPath, "image/jpeg");
            }
    
            private static void CreateImageThumbnail(string originalPath, string copyPath)
            {
                // Generate and save thumbnail jpeg
            }
        }
    }



    Сделаем содержимое сообщества лучше, вместе!


    • Изменено YatajgaEditor 27 апреля 2014 г. 20:10 Дополнил
    • Помечено в качестве ответа RomanKoff 28 апреля 2014 г. 13:33
    27 апреля 2014 г. 20:05
    Модератор

Все ответы

  • Вызывайте метод в блокировке.

    using System.Web.Mvc;
    
    namespace MvcApplication.Controllers
    {
        public class DefaultController : Controller
        {
            private static readonly object lockObject = new object();
    
            public ActionResult GetImageThumbnail(string originalPath)
            {
                string copyPath = originalPath + ".th.jpg";
                if (!System.IO.File.Exists(copyPath))
                {
                    lock (lockObject)
                    {
                        if (!System.IO.File.Exists(copyPath))
                        {
                            CreateImageThumbnail(originalPath, copyPath);
                        }
                    }   
                }
    
                return this.File(copyPath, "image/jpeg");
            }
    
            private static void CreateImageThumbnail(string originalPath, string copyPath)
            {
                // Generate and save thumbnail jpeg
            }
        }
    }



    Сделаем содержимое сообщества лучше, вместе!


    • Изменено YatajgaEditor 27 апреля 2014 г. 20:10 Дополнил
    • Помечено в качестве ответа RomanKoff 28 апреля 2014 г. 13:33
    27 апреля 2014 г. 20:05
    Модератор
  • Спасибо, я примерно так и думал. А какая роль у lockObject? Дело в том, что экшен обрабатывает не одну картинку. Т. е. может прийти запрос на создание другой миниатюры и ему нельзя отказывать. Могу ли я в качестве lockObject каким либо образом использовать copyPath для блокировки только не уникальных запросов?
    28 апреля 2014 г. 11:50
  • А другая картинка у вас не по Path определяется? Если да, то всё нормально. Алгоритм такой:

    Если нужная картинка уже есть, никаких блокировок не происходит.

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


    Сделаем содержимое сообщества лучше, вместе!

    28 апреля 2014 г. 11:57
    Модератор
  • Тут есть один минус. Если вначале придёт слишком много запросов, то потоки будут блокированы, и освободятся только после того как метод создаст рисунок. Правда они не будут занимать ЦП, но и новые запросы не смогут обрабатывать.

    Сделаем содержимое сообщества лучше, вместе!

    28 апреля 2014 г. 12:00
    Модератор
  • Спасибо, принцип понял.
    28 апреля 2014 г. 13:34