开发者

Parallel.ForEach x of x

So I'm working in c# 4.0 WPF application and using parallel foreach loops to export data to a database using a database repository I created. I have got the export working with parallel foreach using a progress bar but would like to be able to give more in depth details of the progress like exporting item 5 of 25. The problem i've encountered is a obvious one, because it is running in parallel the counter does not work, i.e. the total will say something like

exporting 0 of 25
exporting 0 of 25
...
exporting 5 of 25
exporting 5 of 25

Can anyone give any guidence of how to get the behaviour working within开发者_开发问答 a parallel loop like this:

int runningTotal = 0;
Parallel.ForEach(source, x =>
{
    Repository.Commit(x);
    runningTotal++;
    progressReporter.ReportProgress(() =>
    {
        //Progress bar update
        this.progressFile.Value++;
        this.lblProgress.Text = String
            .Format("Exporting Source {0} of {1}", runningTotal, source.Count)
    });
});

Hope this shows what I'm hoping to achieve.

Thanks


As you're using the same data from multiple thread, you should protect it's access with a locking mechanism. It can be done easily by using the lock construct.

However, it might be a little too overkill for your need. As you're only incrementing a value, a simple System.Threading.Interlocked.Increment would work. On msdn.

int runningTotal = 0;
Parallel.ForEach(source, x =>
{
    Repository.Commit(x);
    Interlocked.Increment(ref runningTotal);
    progressReporter.ReportProgress(() =>
    {
        //Progress bar update
        Interlocked.Increment(ref this.progressFile.Value);
        this.lblProgress.Text = String
            .Format("Exporting Source {0} of {1}", runningTotal, source.Count)
    });
});

EDIT: I've made a sample in WPF.

Window.xaml :

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button Grid.Row="0" Click="Button_Click">Click me</Button>
        <TextBlock Grid.Row="1">
            <TextBlock.Text>
                <MultiBinding StringFormat="Progress: {0}/{1}">
                    <Binding Path="ProgressValue" RelativeSource="{RelativeSource AncestorType=Window, Mode=FindAncestor}" />
                    <Binding Path="ProgressMax" RelativeSource="{RelativeSource AncestorType=Window, Mode=FindAncestor}" />
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </Grid>
</Window>

Window.xaml.cs

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
    }

    int progressValue;
    public int ProgressValue
    {
        get { return (this.progressValue); }
        set { this.progressValue = value; this.raisePropertyChanged("ProgressValue"); }
    }

    public int ProgressMax
    {
        get { return (100); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    void raisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            int counter = 0;

            Parallel.ForEach(Enumerable.Range(1, 100), i =>
            {
                Interlocked.Increment(ref counter);
                    this.ProgressValue = counter;
                Thread.Sleep(25);
            });
        });
    }
}

I'm simply using bindings to display a string indicating the work progress. Everything is stored in the Window which implements INotifyPropertyChanged to force bindings to refresh and display the updated value. It can easily be moved to it's own class which will implement INotifyPropertyChanged for a cleaner code.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜