Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#委托多线程比单线程慢?_C#_.net_Multithreading_Image Processing_Delegates - Fatal编程技术网

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

C#委托多线程比单线程慢?,c#,.net,multithreading,image-processing,delegates,C#,.net,Multithreading,Image Processing,Delegates,我目前正在编写一个C#应用程序来演示并行计算在单线程应用程序上的加速。我的例子是图像的中值模糊。但是,让更多线程工作会显著降低应用程序的速度(单线程60秒,多线程75秒)。考虑到我目前的方法,我不知道如何改进多线程处理过程。对于这篇文章中的长代码,我深表歉意 我目前的做法是: 首先,我计算每个线程需要处理多少像素来平衡工作,DateTime计算是为了知道单线程需要花费多少时间,多线程需要花费多少时间: public void blurImage(int cores) {

我目前正在编写一个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);
    }
每个线程模糊其像素集,并将结果保存到新的颜色列表中,结果保存到结果对象以及startpixel和当前操作中,以便程序知道所有线程何时完成:

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;
    }
private void blurPixels(位图位图、int startPixel、int endPixel、int窗口、BlurResult结果、BlurOperation操作)
{
列表颜色=新列表();
对于(int i=startPixel;i
像素模糊器计算每个颜色通道的中值并返回:

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;
    }
公共静态颜色ShadePixel(int x、int y、位图图像、int窗口)
{
列表红色=新列表();
列表绿色=新列表();
列表蓝色=新列表();
int xBegin=Math.Max(x-window,0);
int-yBegin=Math.Max(y-window,0);
int xEnd=Math.Min(x+窗口,image.Width-1);
int yEnd=Math.Min(y+窗口,图像高度-1);
对于(int-tx=xBegin;tx
在回调时,我们返回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);
    }
private void finish(IAsyncResult iar)
{
Application.Current.Dispatcher.BeginInvoke(新的异步回调(更新),iar);
}
私有无效更新(IAsyncResult iar)
{
BlurResult=(BlurResult)iar.AsyncState;
更新图像(结果。\像素,结果。\开始像素,结果。\操作);
}
私有void updateImage(列表颜色、int startPixel、模糊操作)
{
DateTime updateTime=DateTime.Now;
_操作。移除(操作);
int end=startPixel+colors.Count;
对于(int i=startPixel;i

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

经过思考,我发现我的逻辑是可靠的,但我没有向每个线程发送深度副本。在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);

我可以看到加速多线程

尝试使用
Stopwatch
类而不是
DateTime
来准确测量性能。仅仅因为你可以在一个任务中抛出更多的线程,并不意味着你应该这样做。不用说,如果您的线程试图访问公共资源,这将产生有害影响。如果您启动多个线程,那么您将有管理线程池的开销,列表还将继续。由于每个线程都使用自己的对象,因此它们不会访问相同的内存。因此,使用的唯一公共资源是生成的图像。当我测量这个时间并从总时间中减去它时,这个开销并不存在于60秒和75秒之间。我并不期待完美的8倍加速,但我确实期待一个无加速。这怎么会更慢呢?从您发布的代码来看,不清楚作业是在什么时候委托给辅助线程的(我想这发生在
BlurOperation.BeginInvoke()
。您可以发布代码吗?'BlurOperation.BeginInvoke()'只是一个委托,它启动了'blurPixels()'无效。
operation.BeginInvoke(new Bitmap(_processedImage), startPixel, numberOfPixels, _windowSize, result, operation, new AsyncCallback(finish), result);