Parallel.ForEach x of x - PullRequest
       1

Parallel.ForEach x of x

3 голосов
/ 15 февраля 2011

Итак, я работаю в приложении c # 4.0 WPF и использую параллельные циклы foreach для экспорта данных в базу данных с использованием созданного мной хранилища базы данных.Я получил экспорт, работающий с параллельным foreach с использованием индикатора выполнения, но хотел бы иметь возможность дать более подробную информацию о ходе выполнения, например, при экспорте пункта 5 из 25. Проблема, с которой я столкнулся, очевидна, поскольку она выполняетсяпараллельно счетчик не работает, то есть итоговое значение скажет что-то вроде

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

Может ли кто-нибудь подсказать, как заставить поведение работать в параллельном цикле следующим образом:

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)
    });
});

Надеюсь, это показывает, чего я надеюсь достичь.

Спасибо

1 Ответ

9 голосов
/ 15 февраля 2011

Поскольку вы используете одни и те же данные из нескольких потоков, вы должны защитить их доступ с помощью механизма блокировки.Это можно легко сделать с помощью конструкции lock.

Однако, это может быть слишком излишним для ваших нужд.Поскольку вы только увеличиваете значение, будет работать простой System.Threading.Interlocked.Increment. 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)
    });
});

РЕДАКТИРОВАТЬ: я сделал образец в 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);
            });
        });
    }
}

Я просто использую привязки для отображения строки, показывающей ход работы.Все хранится в окне, которое реализует INotifyPropertyChanged, чтобы принудительно обновлять привязки и отображать обновленное значение.Его можно легко переместить в собственный класс, который будет реализовывать INotifyPropertyChanged для более чистого кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...