I am using the .NET Chart Control library that comes with .NET 4.0 Beta 2 to create and save images to disk on a background thread. I am not showing the chart on the screen, however, simply creating a chart, saving it to disk, and destroying it. Something like this:
public void GeneratePlot(IList<DataPoint> series, Stream outputStream) {
using (var ch = new Chart()) {
ch.ChartAreas.Add(new ChartArea());
var s = new Series();
foreach (var pnt in series) s.Points.Add(pnt);
ch.Series.Add(s);
ch.SaveImage(outputStream, ChartImageFormat.Png);
}
}
It was taking about 300 - 400 ms to create and save each chart. I have potentially hundreds of charts to create, so I thought I would use Parallel.For()
to parallelize these tasks. I have an 8 core machine, however, when I try to create 4 charts at a time, my chart create/save time increases to anywhere from 800 to 1400 ms, almost all of which is consumed by Chart.SaveImage
.
I thought this might be a limitation of disk I/O, so to test that I changed the last line to:
ch.SaveImage(Stream.Null, ChartImageFormat.Png);
Even writing to a null stream the performance is still about the same (800 - 1400 ms).
Am I not supposed to create images on background threads in parallel with this library, or am I doing something wrong?
Thanks
EDIT: Added Complete Code Sample
Simply change the flag passed to CreateCharts()
to test parallel versus serial.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms.DataVisualization.Charting;
namespace ConsoleChartTest
{
class Program
{
public static void GeneratePlot(IEnumerable<DataPoint> series, Stream outputStream)
{
long beginTime = Environment.TickCount;
using (var ch = new Chart())
{
ch.ChartAreas.Add(new ChartArea());
var s = new Series();
foreach (var pnt in series)
s.Points.Add(pnt);
ch.Series.Add(s);
long endTime = Environment.TickCount;
long createTime = endTime - beginTime;
beginTime = Environment.TickCount;
ch.SaveImage(outputStream, ChartImageFormat.Png);
endTime = Environment.TickCount;
long saveTime = endTime - beginTime;
Console.WriteLine("Thread Id: {0,2} Create Time: {1,3} Save Time: {2,3}",
Thread.CurrentThread.ManagedThreadId, createTime, saveTime);
}
}
public static void CreateCharts(bool parallel)
{
var data = new DataPoint[20000];
for (int i = 0; i < data.Length; i++)
{
data[i] = new DataPoint(i, i);
}
if (parallel)
{
Parallel.For(0, 10, (i) => GeneratePlot(data, Stream.Null));
}
else
{
for (int i = 0; i < 10; i++)
GeneratePlot(data, Stream.Null);
}
}
static void Main(string[] args)
{
Console.WriteLine("Main Thread Id: {0,2}", Thread.CurrentThread.ManagedThreadId);
long beginTime = Environment.TickCount;
CreateCharts(false);
long endTime = Environment.TickCount;
Console.WriteLine("Total Time: {0}", endTime - beginTime);
}
}
}