使用多线程的线程池
问题描述:
我有以下代码:使用多线程的线程池
private static void SplitTilesRecursive(Image original, int level)
{
int mapWidth = GetMapWidth(level);
int tilesOnSide = mapWidth/TileSize;
using (Image resized = ResizeImage(original, new Size(mapWidth, mapWidth)))
{
for (int x = 0; x < tilesOnSide; x++)
for (int y = 0; y < tilesOnSide; y++)
{
CropAndSaveTile(resized, x, y, level);
}
}
if (level > 0)
SplitTilesRecursive(original, level - 1);
}
private static void CropAndSaveTile(Image image, int x, int y, int level)
{
var info = (CropInfo) o;
var cropArea = new Rectangle(x * TileSize, y * TileSize, TileSize, TileSize);
using (var bmpImage = new Bitmap(image))
using (Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat))
{
string filename = String.Format(TileFilename, level, x, y);
// the Portable Network Graphics (PNG) encoder is used implicitly
bmpCrop.Save(Path.Combine(OutputDir, filename));
Console.WriteLine("Processed " + filename);
}
}
的方法CropAndSaveTile
需要一段时间,所以我想拆分任务关闭使用线程池一个新的线程。我试图用Task.Factory.StartNew
来完成这个。问题是我需要将这4个参数传递给线程,所以我必须创建一个可以投射到对象的类。
private class CropInfo
{
public CropInfo(Image image, int x, int y, int level)
{
Image = image;
X = x;
Y = y;
Level = level;
}
public Image Image { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int Level { get; set; }
}
private static void SplitTilesRecursive(Image original, int level)
{
// ...
using (Image resized = ResizeImage(original, new Size(mapWidth, mapWidth)))
{
for (int x = 0; x < tilesOnSide; x++)
for (int y = 0; y < tilesOnSide; y++)
{
Task.Factory.StartNew(CropAndSaveTile, new CropInfo(resized, x, y, level));
}
}
// ...
}
private static void CropAndSaveTile(object o)
{
var info = (CropInfo) o;
// ...
}
这几乎奏效。问题是new Bitmap(info.Image)
会抛出一个ArgumentException
(参数无效)。我已经测试了这个而不使用Task.Factory.StartNew
,而是直接使用CropAndSaveTile(new CropInfo(resized, x, y, level));
来调用该方法,它工作正常。 StartNew
和线程运行之间发生了一些事情。这可能是由于SplitTilesRecursive
结束循环以及resized
被处置时造成的同步问题吗?如果不是,我怎样才能正确地将多个参数传递给线程来作为线程池的一部分?
答
为什么你需要创建一个类?你可以这样做:
Task.Factory.StartNew(()=>CropandSaveTile(resized, y, y, level));
该语言将为您创建一个类作为“闭包”。
答
尝试使用的x
和y
本地副本内循环:
for (int x = 0; x < tilesOnSide; x++)
for (int y = 0; y < tilesOnSide; y++)
{
int x1 = x;
int y1 = y;
Task.Factory.StartNew(() => CropAndSaveTile(resized, x1, y1, level));
}
这保证了每个拉姆达看到一对单独的x
和y
值。
你是否对所有任务使用'resized'的相同实例? – Tudor 2012-07-26 15:56:33