LockBits() выбрасывает "Недостаточно памяти" в параллельном Foreach?

Я новичок в C# и параллельной обработке. Я пытаюсь обработать кучу изображений, и я написал методы для обработки. И я добавил параллельный цикл foreach в список изображений, как показано ниже

    Parallel.ForEach(Directory.GetFiles(path), new ParallelOptions { MaxDegreeOfParallelism = 2 }, fileName =>
            {
                List<string> tempList = new List<string>();
                using (Bitmap imageBitmap= new Bitmap(fileName))
                {
                    using (ImageProcessor imageProcessor= new ImageProcessor ())
                    {
                        tempList = imageProcessor.ProcessImage(imageBitmap);
                    }
                }
                if (tempList.Count != 0)
                    allElements.Add(tempList.FirstOrDefault());
            });

В одном из методов, которые я использовал LockBits способ получить BitMapData изображения и копирование этих данных в byte[] но метод вызывает исключение, код метода

   private byte[] ImageToByteArray(Bitmap b, out int stride)
    {
        object sync = new object();
        BitmapData bd;
        lock (sync)
        {
            Rectangle rect = new Rectangle(0, 0, b.Width, b.Height);
            bd = b.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);//This line throwing the exception.

            try
            {
                byte[] pxl = new byte[bd.Stride * b.Height];
                Marshal.Copy(bd.Scan0, pxl, 0, bd.Stride * b.Height);
                stride = bd.Stride;
                return pxl;
            }
            finally
            {
                b.UnlockBits(bd);
            }
        }
    }

Я пытался lock код, который использует LockBits метод, так что одновременно только один поток использует код и, следовательно, память.

Я также пытался использовать lock с вызовом методов из родительского метода, как

    public List<string> ProcessImage(BitMap image)
    {
        object sync = new object();
        int stride;
        byte[] rawImg;
        using (image)
        {
            lock (sync)
            {
                rawImg = ImageToByteArray(image, out stride);
            }
            processingImg = new ProcessImage(rawImg, image.Width, image.Height);
        }
  }

но все же исключение есть. Исключение не дает мне никакой трассировки стека или только объяснение. Исключение, которое я получаю, Out Of Memory,

Я столкнулся с этим ответом, и когда я уменьшил MaximumDegreeOfParallelism это сработало правильно.

В общем, я хотел знать, 1) почему код бросал Out Of Memory исключение для более чем 2 потоков даже есть lock по коду? 2) И возможно ли избежать этого исключения, если я увеличу DegreeOfParallelism? Любая помощь будет отличной.


В случае любой путаницы не стесняйтесь комментировать.

1 ответ

  1. Вопрос в том, насколько велики изображения, которые вы хотите обработать. Может быть, они просто слишком большие. Мой опыт также показывает, что вызов LockBits выделяет дополнительный объем памяти - фактически он удваивает объем выделенной памяти. Вы пытались обработать очень маленькую картинку?

  2. Блокировка в вашем коде ничего не делает, потому что вы блокируете локальные переменные. Если вы хотите синхронизировать доступ к критическому разделу между потоками и хотите сделать это с блокировкой, вам нужно использовать объект, который используется всеми этими потоками. В вашем случае объект синхронизации должен быть объявлен как приватное поле класса ImageProcessor.

  3. Я думаю, что увеличение DegreeOfParallelism не поможет или даже ухудшит ситуацию, потому что вашему коду потребуется больше памяти для обработки большего количества изображений.

Другие вопросы по тегам