Parallel.For有问题 [英] Have a problem with Parallel.For

查看:75
本文介绍了Parallel.For有问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,



一个图像处理程序,它具有亮度功能等等,可以改变亮度。所以我想使用System.Threading.Tasks库(特别是Parallel.For)实现我的目的并表示正在进行中,最后我们有一个响应式UI。我也是很多谷歌搜索,并找到许多好处主题。但是在处理图像时不要更新进度元素。这个程序的问题在哪里?



XAML代码:

Hi everybody,

An image process program that it has a brightness function and so on for changing brightness. So I want to implement my purpose using System.Threading.Tasks library (particularly Parallel.For) and represent in progress and finally we have a responsive UI. Also I a lot of Googling and find out many benefit topics. But don't update progress element whilst process image. Where is the problem in this program?

XAML code:

<Window x:Class="WpfApp_Tmp.DiagramPic.DiagramPic"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="DiagramPic" Height="600" Width="400">
    <Grid>
        <StackPanel>
            <Button Click="Button_Click_1">Brightness using Ptr</Button>
            <ProgressBar Name="progress" Height="20"></ProgressBar>
            <Image Name="image" Stretch="UniformToFill" />
        </StackPanel>
    </Grid>
</Window>





代码落后:



Code behind:

BitmapSource SetBrightnessWithPtr(BitmapSource bmp, int amount)
{
    WriteableBitmap bDest = null;
    bDest = new WriteableBitmap(bmp);
    bDest.Lock();
    IntPtr buff = bDest.BackBuffer;
    int stride = bDest.BackBufferStride;

    int nWidth = bmp.PixelWidth;
    int nHeight = bmp.PixelHeight;

    double percentage = 100 / (progress.Maximum = nHeight);
    progress.Value = 0.0;

    //Task.Factory.StartNew(delegate
    //{
        Parallel.For(0, nHeight, y =>
        //for(int y=0;y<nHeight;y++)
        {
            IntPtr buffer = buff;
            buffer += y * stride;

            for (int x = 0; x < nWidth; x++)
            {
                Int32 abgr = Marshal.ReadInt32(buffer);

                int r = (abgr & 0x000000ff) + amount;
                int g = ((abgr & 0x0000ff00) >> 0x08) + amount;
                int b = ((abgr & 0x00ff0000) >> 0x10) + amount;
                //int a = (byte)((abgr & 0xff000000) >> 0x18);

                r = Math.Max(Math.Min(r, 255), 0);
                g = Math.Max(Math.Min(g, 255), 0);
                b = Math.Max(Math.Min(b, 255), 0);
                //a = 0xff;

                abgr |= r;
                abgr |= g << 0x08;
                abgr |= b << 0x10;
                //abgr |= a << 0x18;

                Marshal.WriteInt32(buffer, abgr);

                buffer += 4;
            }

            progress.Dispatcher.BeginInvoke((Action)delegate { this.Title = Convert.ToByte(++progress.Value * percentage).ToString(); });
        });
    //});

    //bDest.AddDirtyRect(new Int32Rect(0, 0, bDest.PixelWidth, bDest.PixelHeight));
    bDest.Unlock();

    return bDest;
}

private void Button_Click_1(object sender, RoutedEventArgs e)
{
    opening();

    int startTime = System.Environment.TickCount;

    if (image.Source != null)
        image.Source = SetBrightnessWithPtr(image.Source as BitmapSource, 128);

    this.Title += " " + (System.Environment.TickCount - startTime).ToString();
}

void opening()
{
    Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
    ofd.Filter = "All images|*.bmp;*.jpg;*.png|Bitmap|*.bmp|Jpeg|*.jpg|Png|*.png";
    if (ofd.ShowDialog().Value)
    {
        Uri imageUri = new Uri(ofd.FileName, UriKind.Absolute);

        this.image.Source = new BitmapImage(imageUri);
    }
}





非常感谢您的帮助。



Your help very appreciated.

推荐答案

我想你可能会误解 Parallel.For()的目的。它不是在后台执行任务而只是并行执行。公平地说, MSDN文章 [ ^ ]没有直截了当地说,但它说:

I think you might misunderstand the purpose of Parallel.For(). It is not to execute tasks in the background but merely in parallel. To be fair, the MSDN article[^] doesn't state that outright, but it says:
Quote:

执行for(For in Visual Basic)循环迭代可以并行运行。

Executes a for (For in Visual Basic) loop in which iterations may run in parallel.



这意味着即使并行性也不能得到保证(我知道它们变得很少见但想到单核CPU)并且调用线程实际上可能用于循环执行。此外, For()返回 ParallelLoopResult [ ^ ],它不会给你任何取消或等待完成的方法(请注意 IsCompleted 表示过早完成),这对于异步API来说是不常见的。最后,一个简短的测试很容易证实这种行为:


This does imply that even parallelism is not guaranteed (I know they are becoming rare but think of single core CPUs) and the calling thread may actually be used for loop execution. Furthermore, For() returns a ParallelLoopResult[^] which doesn't give you any way of cancelling or waiting for completion (notice how IsCompleted indicates premature completion) which would be unusual at best for an asynchronous API. Finally, a short test easily confirms this behavior:

static void Main(string[] args)
{
    Console.WriteLine("Invoking Parallel.For() on thread {0}",
                        Thread.CurrentThread.ManagedThreadId);

    Parallel.For(0, Environment.ProcessorCount, i =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("    Wasted 1 sec on thread {0}",
                            Thread.CurrentThread.ManagedThreadId);
    });

    Console.WriteLine("Parallel.For() returned on thread {0}",
                        Thread.CurrentThread.ManagedThreadId);
    Console.ReadKey(true);
}



最后两行在循环完成之前不会执行。长话短说,你真正想要的是 任务 [ ^ ](或其他一些异步运行代码的方式,如 QueueUserWorkItem() [ ^ ]或启动你自己的后台线程。)


The last two lines will not execute until the completion of the loop. Long story short, what you are really looking for is Task[^] (or some other way of running code asynchronously like QueueUserWorkItem()[^] or spinning up your own background thread).


这篇关于Parallel.For有问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆