C#委托多线程比单线程慢吗?

时间:2017-05-07 22:18:43

标签: c# .net multithreading image-processing delegates

我目前正在编写一个C#应用程序来演示单线程应用程序上并行计算的加速。我的情况是图像的中位模糊。但是让更多的线程工作会显着减慢应用程序的速度(60秒单线程与75秒多线程)。鉴于我目前的方法,我不知道如何改进多线程的过程。对于这篇文章中的长代码,请提前抱歉。

我目前的做法:

首先,我计算每个线程需要处理多少像素才能使工作均匀,DateTime计算是知道单线程传递了多少时间以及多线程传递了多少时间:

public void blurImage(int cores)
    {
        _startTotal = DateTime.Now;

        int numberOfPixels = _originalImage.Width * _originalImage.Height;

        if (cores>=numberOfPixels)
        {
            for (int i = 0; i < numberOfPixels; i++)
            {
                startThread(0, numberOfPixels);
            }
        }
        else
        {
            int pixelsPerThread = numberOfPixels / cores;

            int threshold = numberOfPixels - (pixelsPerThread * cores);

            startThread(0, pixelsPerThread + threshold);

            for (int i = 1; i < cores; i++)
            {
                int startPixel = i * pixelsPerThread + threshold;
                startThread(startPixel, startPixel + pixelsPerThread);
            }
        }

        _SeqTime = DateTime.Now.Subtract(_startTotal);
    }

startThread方法启动一个线程并将结果保存到一个特殊的类对象中,这样它就可以合并到一个图像中,我在每个线程中传递一个输入图像的副本。

private void startThread(int startPixel, int numberOfPixels)
    {
        BlurOperation operation = new BlurOperation(blurPixels);
        _operations.Add(operation);

        BlurResult result = new BlurResult();

        operation.BeginInvoke((Bitmap)_processedImage.Clone(), startPixel, numberOfPixels, _windowSize, result, operation, new AsyncCallback(finish), result);
    }

每个线程模糊它们的像素集并将结果保存到新的颜色列表中,结果保存到结果对象以及startpixel和当前操作中,因此程序知道所有线程何时完成: / p>

private void blurPixels(Bitmap bitmap, int startPixel, int endPixel, int window, BlurResult result, BlurOperation operation)
    {

        List<Color> colors = new List<Color>();

        for (int i = startPixel; i < endPixel; i++)
        {

            int x = i % bitmap.Width;
            int y = i / bitmap.Width;

            colors.Add(PixelBlurrer.ShadePixel(x, y, bitmap, window));
        }

        result._pixels = colors;
        result._startPixel = startPixel;
        result._operation = operation;
    }

PixelBlurrer计算每个颜色通道的中位数并将其返回:

public static Color ShadePixel(int x, int y, Bitmap image, int window)
    {
        List<byte> red = new List<byte>();
        List<byte> green = new List<byte>();
        List<byte> blue = new List<byte>();

        int xBegin = Math.Max(x - window, 0);
        int yBegin = Math.Max(y - window, 0);

        int xEnd = Math.Min(x + window, image.Width - 1);
        int yEnd = Math.Min(y + window, image.Height - 1);

        for (int tx = xBegin; tx < xEnd; tx++)
        {
            for (int ty = yBegin; ty < yEnd; ty++)
            {
                Color c = image.GetPixel(tx, ty);

                red.Add(c.R);
                green.Add(c.G);
                blue.Add(c.B);
            }
        }

        red.Sort();
        green.Sort();
        blue.Sort();

        Color output = Color.FromArgb(red[red.Count / 2], green[green.Count / 2], blue[blue.Count / 2]);
        return output;
    }
回调

,我们返回GUI线程并将所有像素合并到结果图像中。最后,一个事件被称为告诉我的表单过程已完成:

private void finish(IAsyncResult iar)
    {
        Application.Current.Dispatcher.BeginInvoke(new AsyncCallback(update), iar);
    }

    private void update(IAsyncResult iar)
    {
        BlurResult result = (BlurResult)iar.AsyncState;
        updateImage(result._pixels, result._startPixel, result._operation);
    }

    private void updateImage(List<Color> colors, int startPixel, BlurOperation operation)
    {
        DateTime updateTime = DateTime.Now;

        _operations.Remove(operation);

        int end = startPixel + colors.Count;

        for (int i = startPixel; i < end; i++)
        {
            int x = i % _processedImage.Width;
            int y = i / _processedImage.Width;

            _processedImage.SetPixel(x, y, colors[i - startPixel]);
        }

        if (_operations.Count==0)
        {
            done(this, null);
        }

        _SeqTime += DateTime.Now.Subtract(updateTime);
    }

有什么想法?我尝试使用Parallel.For代替委托,但这使情况变得更糟。有没有办法通过多线程加速中位数模糊,或者这是一个失败的案例?

1 个答案:

答案 0 :(得分:0)

经过一番思考后,我发现我的逻辑是可靠的,但我没有向每个线程发送深层副本。在StartThread中更改此行后:

operation.BeginInvoke((Bitmap)_processedImage.Clone(), startPixel, numberOfPixels, _windowSize, result, operation, new AsyncCallback(finish), result);

到此:

operation.BeginInvoke(new Bitmap(_processedImage), startPixel, numberOfPixels, _windowSize, result, operation, new AsyncCallback(finish), result);

我可以看到加速多线程