Parallel.ForEach x of x

Parallel.ForEach x of x

问题描述:

因此,我正在使用c#4.0 WPF应用程序并使用并行foreach循环将数据导出到使用我创建的数据库存储库的数据库。我已经得到了使用进度条的并行foreach的出口工作,但希望能够给出更深入的进展细节,例如导出第25项中的第5项。我遇到的问题显而易见,因为它正在运行并行计数器不工作,即总量将这样说Parallel.ForEach x of x

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

希望这显示了我希望达到的目标。

感谢

+0

ProgressReporter类:http://nitoprograms.blogspot.com.es/2010/06/reporting-progress-from-tasks.html – Kiquenet 2012-08-24 09:52:35

当你使用多个线程相同的数据,你应该保护它与锁定机构的访问。它可以通过使用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为更干净的代码。

+0

为什么使用runningTotal,只需将Progress Maximum设置为source.Count并使用progressFile.Value放入runningTotal – Stecya 2011-02-15 11:34:04