2

我理解这个问题可能太笼统了。但是我尝试了很多东西,但我无法弄清楚如何解决这个问题。

我正在使用 ConcurrentQueue 进行多线程操作。一个线程正在从服务器下载图像并将其保存到队列中。这是代码:

 public static void DownloadImage()
    {
        string baseUrl = "http://someurl";
        //int numIterations = 5;

        HttpWebRequest request = null;
        foreach (var fileName in fileNames)
        {
                string url = string.Format(baseUrl, fileName);
                request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "GET";
                request.ContentType = "application/x-www-form-urlencoded";
                var response = (HttpWebResponse)request.GetResponse();
                Stream stream = response.GetResponseStream();
                img = Image.FromStream(stream);
                ImageFileName FileNameImage = new ImageFileName(fileName, img);
                ImageQueue.Enqueue(FileNameImage);
                Console.WriteLine("Count after Enqueue: {0}", ImageQueue.Count);

         }

另一个线程从队列中获取图像并将它们保存在目标文件夹中。这是代码:

public static void SaveImage()
    {
        while (true)
        {
            if (!ImageQueue.IsEmpty)
            {
                foreach (var newobject2 in ImageQueue)
                {

                    Image img2 = newobject2.Image;
                    img2.Save("C:\\path" + newobject2.ImageName);
                    ZoomThumbnail = img2;
                    ZoomSmall = img2;
                    ZoomLarge = img2;

                    ZoomThumbnail = GenerateThumbnail(ZoomThumbnail, 86, false);
                    ZoomSmall = GenerateThumbnail(ZoomSmall, 400, false);
                    ZoomLarge = GenerateThumbnail(ZoomLarge, 1200, false);

                    ZoomThumbnail.Save("C:\\path" + newobject2.ImageName + "_Thumb.jpg");
                    ZoomSmall.Save("C:\\path" + newobject2.ImageName + "_ZoomSmall.jpg");
                    ZoomLarge.Save("C:\\path" + newobject2.ImageName + "_ZoomLarge.jpg");
                    ImageFileName imgobject3 = new ImageFileName();
                    ImageQueue.TryDequeue(out imgobject3);
                    Console.WriteLine("Count after Deque: {0}", ImageQueue.Count);

                }


            }


        }

    }

我从 Button_Click() 调用这两个线程,如下所示:

Thread DownloadThread = new Thread(DownloadImage);
  DownloadThread.Start();
  Thread SaveThread = new Thread(SaveImage);
  SaveThread.Start();

每当队列达到 68 个计数时,我都会收到 MemoryFull 错误。我不确定如何避免这种情况。我尝试使用 Thread.Sleep 来避免这种情况。例如,我试过:循环Thread.Sleep(500)之后。foreach每当我在里面尝试它时,foreach它在任何给定点上都可以正常工作ImageQueue.Count = 1。我哪里错了?

4

5 回答 5

1

你从来没有真正从队列中删除你的图像。你遍历它们,但你永远不会让它们出队。您还有一个问题,即在枚举队列时,只要队列中当前没有更多项目,可枚举就会停止。你不想这样做,你可能还没有完成。

您想要做的是使用 aBlockingCollection而不是 a ConcurrentQueue,这样如果当前没有更多项目,您将等待更多,而不是停止。完成此操作后,您可以使用foreach(var item in queue.GetConsumingEnumerable()). 这会进行所有需要的更改。它在您迭代时从队列中删除项目,如果当前没有项目,它会等待更多项目。

除了进行此更改(如 Guffa 的回答中所述)外,您还需要处理图像对象。完成图像后,您可以在循环体的末尾处理它们。

于 2014-04-07T15:44:05.943 回答
0

您正在创建许多Image您不处置的对象。您应该调用Dispose您创建的每个缩略图。

此外,您出列的对象包含一个Image在您不再需要时应该丢弃的对象。


旁注:您不应该枚举队列中的项目并将循环内的项目出队。而是使用TryDequeue循环本身中的方法:

ImageFileName imgobject2;
while (ImageQueue.TryDequeue(out imgobject2)) {
  ...
}

另一个注意事项:当队列为空时,您的代码将进入一个紧密循环,使用大量 CPU 能力以非常快速地重复进行相同的检查。您应该使用一种机制来暂停线程,直到队列发生某些事情,或者至少在再次检查队列之前休眠一段时间。

于 2014-04-07T15:35:34.717 回答
0

You might want to look at the BlockingCollection class (here), which I've successfully used for this kind of "producer-consumer" pattern.

Something (a producer) puts items into the collection, with one or more "consumer" b/g threads taking the next available item(s) out of the collection and doing something with them. You can also configure the number of consumer threads to use (e.g. for a multi-core PC).

于 2014-04-07T15:53:26.257 回答
0

您应该在完成图像后处理,因此在 ZoomLarge 语句之后,因为之后您不再使用它。使用 Generate 语句创建新图像。

于 2014-04-07T15:43:14.200 回答
0

1.您似乎保留了对所有图像的引用,这些图像将它们保存在内存中,不允许垃圾收集器收集它们。

此外,在您使用完对象后,您可以明确地处置它们,如下所示:

Image img2 = newobject2.Image;
img2.Dispose();

2.你所做的是每次你在一个while循环中枚举你所有的图像,我不确定这是你想要的。您应该做的是尝试使项目出队:

FileImageName myImage;
ImageQueue.TryDequeue(out myImage);

if (myImage != null)
{
// Do work on the image
}
于 2014-04-07T15:45:20.480 回答