我正在尝试理解我最近在项目中遇到的一个问题。我正在使用Aurigma库来调整图像大小。它用于单线程模式,在计算过程中只生成一个线程。最近我决定转移到ImageMagick项目,因为它是免费和开源的。我在单线程模式下构建了IM并开始测试。起初我想在没有中断的情况下比较它们的性能,所以我创建了一个对进程及其线程具有高优先级的测试。另外,我将亲和力设置为一个核心。我得到的IM比Aurigma快~25%。但是,与我添加的线程相比,更少的IM对Aurigma有优势。
我的项目是一个Windows服务,启动大约7-10个子进程。每个进程都有2个线程来处理图像。当我将测试作为两个不同的进程运行,每个进程有2个线程时,我注意到IM的工作比Aurigma差了大约5%。
也许我的问题不是很详细,但这个范围对我来说有点新意,我很乐意为进一步调查指明方向。如果一个程序在一个进程中的一个线程上运行,那么如何运行得更快,但如果它在同一时间在多个进程中运行则会更糟。
例如,
Au:8个进程x 2Th(每个线程20个任务)= 320个任务,持续245秒
IM:8个进程x 2Th(每个线程20个任务)= 320个任务,持续280秒
Au:4个进程x 2Th(每个线程20个任务)= 160个任务,121秒
IM:4个进程x 2Th(每个线程20个任务)= 160个任务,141秒
如果我们有更多的1个过程,我们可以看到Au工作得更好,但是在单个过程模式下:Au处理一个任务2,2秒,IM处理1,4秒,总和时间对IM更好
private static void ThreadRunner(
Action testFunc,
int repeatCount,
int threadCount
)
{
WaitHandle[] handles = new WaitHandle[threadCount];
var stopwatch = new Stopwatch();
// warmup
stopwatch.Start();
for (int h = 0; h < threadCount; h++)
{
var handle = new ManualResetEvent(false);
handles[h] = handle;
var thread = new Thread(() =>
{
Runner(testFunc, repeatCount);
handle.Set();
});
thread.Name = "Thread id" + h;
thread.IsBackground = true;
thread.Priority = ThreadPriority.Normal;
thread.Start();
}
WaitHandle.WaitAll(handles);
stopwatch.Stop();
Console.WriteLine("All Threads Total time taken " + stopwatch.ElapsedMilliseconds);
}
private static void Runner(
Action testFunc,
int count
)
{
//Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2); // Use only the second core
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal;
Process.GetCurrentProcess().PriorityBoostEnabled = false;
Thread.CurrentThread.Priority = ThreadPriority.Normal;
var stopwatch = new Stopwatch();
// warmup
stopwatch.Start();
while(stopwatch.ElapsedMilliseconds < 10000)
testFunc();
stopwatch.Stop();
long elmsec = 0;
for (int i = 0; i < count; i++)
{
stopwatch.Reset();
stopwatch.Start();
testFunc();
stopwatch.Stop();
elmsec += stopwatch.ElapsedMilliseconds;
Console.WriteLine("Ticks: " + stopwatch.ElapsedTicks +
" mS: " + stopwatch.ElapsedMilliseconds + " Thread name: " + Thread.CurrentThread.Name);
}
Console.WriteLine("Total time taken " + elmsec + " Thread name: " + Thread.CurrentThread.Name);
}
/// <summary>
/// Entry point
/// </summary>
/// <param name="args"></param>
private static void Main(string[] args)
{
var files = GetFiles(args.FirstOrDefault());
if (!files.Any())
{
Console.WriteLine("Source files were not found.");
goto End;
}
//// Run tests
Console.WriteLine("ImageMagick run... Resize");
Runner(() => PerformanceTests.RunResizeImageMagickTest(files[0]), 20);
Console.WriteLine("Aurigma run... Resize");
Runner(() => PerformanceTests.RunResizeAurigmaTest(files[0]), 20);
Console.WriteLine("ImageMagick run... multi Resize");
ThreadRunner(() => PerformanceTests.RunResizeImageMagickTest(files[0]), 20, 2);
Console.WriteLine("Aurigma run... multi Resize");
ThreadRunner(() => PerformanceTests.RunResizeAurigmaTest(files[0]), 20, 2);
End:
Console.WriteLine("Done");
Console.ReadKey();
}
public static void RunResizeImageMagickTest(string source)
{
float[] ratios = { 0.25f, 0.8f, 1.4f };
// load the source bitmap
using (MagickImage bitmap = new MagickImage(source))
{
foreach (float ratio in ratios)
{
// determine the target image size
var size = new Size((int)Math.Round(bitmap.Width * ratio), (int)Math.Round(bitmap.Height * ratio));
MagickImage thumbnail = null;
try
{
thumbnail = new MagickImage(bitmap);
// scale the image down
thumbnail.Resize(size.Width, size.Height);
}
finally
{
if (thumbnail != null && thumbnail != bitmap)
{
thumbnail.Dispose();
}
}
}
}
}
public static void RunResizeAurigmaTest(string source)
{
float[] ratios = { 0.25f, 0.8f, 1.4f };
//// load the source bitmap
using (ABitmap bitmap = new ABitmap(source))
{
foreach (float ratio in ratios)
{
// determine the target image size
var size = new Size((int)Math.Round(bitmap.Width * ratio), (int)Math.Round(bitmap.Height * ratio));
ABitmap thumbnail = null;
try
{
thumbnail = new ABitmap();
// scale the image down
using (var resize = new Resize(size, InterpolationMode.HighQuality))
{
resize.ApplyTransform(bitmap, thumbnail);
}
}
finally
{
if (thumbnail != null && thumbnail != bitmap)
{
thumbnail.Dispose();
}
}
}
}
}
添加了测试代码。我使用C#/ .NET,ImageMagick通过ImageMagick.Net库工作,对于Aurigma也有一个。对于IM .net lib是在C ++ / CLI上编写的,IM是C.使用了很多语言。
IM的OpenMP已关闭。
答案 0 :(得分:0)
可能是内存缓存问题。有可能以某种方式利用内存的多个线程创建一个场景,即一个线程使另一个线程正在使用的高速缓存内存无效,从而导致停顿。
不纯粹数字运算但依赖大量IO(CPU&lt; - &gt; Memory)的程序更难以分析。