有没有一种方法可以更好地优化ProgressBars的WPF逻辑

时间:2019-08-24 18:21:19

标签: c# wpf logic

每50毫秒执行一次指定的代码块。由于某些我不知道的原因,这特别占用了60%以上的CPU。这是使用Bass WASAPI的频谱分析仪显示的一部分。

由于我有限的编程知识,我只尝试了Thread.Sleep();。它只是破坏了整个程序的帧速率。除了下面提到的代码是罪魁祸首,CPU下降到最大10%,这是可以接受的。

private void _t_Tick(object sender, EventArgs e)
        {
            //Get FFT Data
            int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT8192);
            if (ret < -1) return;
            int x, y;
            int b0 = 0;

            //Calculate FFT data to Frequency
            for (x = 0; x < _lines; x++)
            {
                float peak = 0;
                int b1 = (int)Math.Pow(2, x * 10.0 / (_lines - 1));
                if (b1 > 1023) b1 = 1023;
                if (b1 <= b0) b1 = b0 + 1;
                for (; b0 < b1; b0++)
                {
                    if (peak < _fft[1 + b0]) peak = _fft[1 + b0];
                }
                y = (int)(Math.Sqrt(peak) * 3 * 255 - 4);
                if (y > 255) y = 255;
                if (y < 0) y = 0;
                _spectrumdata.Add((byte)y);
                Thread.SpinWait(64);
           }

           //Send data to the spectrum control file
           if (DisplayEnable) _spectrum.Set(_spectrumdata);
           _spectrumdata.Clear();

        }

    //The culprit that's using a lot of CPU
    public void Set(List<byte> data)
            {
                if (data.Count < 64) return;

                Bar01.Value = data[0];
                Bar02.Value = data[1];
                Bar03.Value = data[2];
                Bar04.Value = data[3];
                Bar05.Value = data[4];
                Bar06.Value = data[5];
                Bar07.Value = data[6];
                Bar08.Value = data[7];
                Bar09.Value = data[8];
                Bar10.Value = data[9];
                Bar11.Value = data[10];
                Bar12.Value = data[11];
                Bar13.Value = data[12];
                Bar14.Value = data[13];
                Bar15.Value = data[14];
                Bar16.Value = data[15];
                Bar17.Value = data[16];
                Bar18.Value = data[17];
                Bar19.Value = data[18];
                Bar20.Value = data[19];
                Bar21.Value = data[20];
                Bar22.Value = data[21];
                Bar23.Value = data[22];
                Bar24.Value = data[23];
                Bar25.Value = data[24];
                Bar26.Value = data[25];
                Bar27.Value = data[26];
                Bar28.Value = data[27];
                Bar29.Value = data[28];
                Bar30.Value = data[29];
                Bar31.Value = data[30];
                Bar32.Value = data[31];
                Bar33.Value = data[32];
                Bar34.Value = data[33];
                Bar35.Value = data[34];
                Bar36.Value = data[35];
                Bar37.Value = data[36];
                Bar38.Value = data[37];
                Bar39.Value = data[38];
                Bar40.Value = data[39];
                Bar41.Value = data[40];
                Bar42.Value = data[41];
                Bar43.Value = data[42];
                Bar44.Value = data[43];
                Bar45.Value = data[44];
                Bar46.Value = data[45];
                Bar47.Value = data[46];
                Bar48.Value = data[47];
                Bar49.Value = data[48];
                Bar50.Value = data[49];
                Bar51.Value = data[50];
                Bar52.Value = data[51];
                Bar53.Value = data[52];
                Bar54.Value = data[53];
                Bar55.Value = data[54];
                Bar56.Value = data[55];
                Bar57.Value = data[56];
                Bar58.Value = data[57];
                Bar59.Value = data[58];
                Bar60.Value = data[59];
                Bar61.Value = data[60];
                Bar62.Value = data[61];
                Bar63.Value = data[62];
                Bar64.Value = data[63];
                Thread.SpinWait(25);
                data.Clear();
            }

此代码可以完美地显示64行频谱分析仪,但是它消耗了大量CPU,有时在双核Intel计算机上甚至超过65%,在双核AMD Mobile cpu上几乎占80%。我很想在CPU上优化此代码。

1 个答案:

答案 0 :(得分:0)

我看不到任何使线程等待的原因,这对性能产生不必要的影响,尤其是在挂起的线程是UI线程时。只需将计时器配置为在预定义的时间间隔内调用回调即可。还优化您的UI,以启用绑定以更新光谱条。

此示例使用ListView,其中StackPanel的水平方向ItemsPanelProgressBar中定义的垂直方向DataTewmplate可视化数据。

计时器是System.Threading.Timer,它在后台线程上执行回调。因此,使用Progress<T>模式(Async in 4.5: Enabling Progress and Cancellation in Async APIs)完成UI的更新,以防止交叉线程。
注意:System.Threading.Timer实现IDisposable

ViewModel.cs

class ViewModel : INotifyPropertyChanged
{
  private ObservableCollection<double> spectrumData;
  public ObservableCollection<double> SpectrumData
  {
    get => this.spectrumData;
    set
    {
      this.spectrumData = value;
      OnPropertyChanged();
    }
  }

  // Constructor
  public void ViewModel()
  {
    // Initialize the data binding source of the ListView
    this.SpectrumData = new ObservableCollection<double>();

    // Creating an instance of Progress<T> captures the current 
    // SynchronizationContext (UI context) to prevent cross threading when updating the ProgressBars (ObservableCollection)
    IProgress<IEnumerable<double>> progressReporter = 
      new Progress<IEnumerable<double>>(value => this.SpectrumData = new ObservableCollection<double>(value));

    // Set timer interval to 50 ms
    var sampleRateTimer = new System.Threading.Timer(OnTimerElapsed, progressReporter, 0, 50);
  }

  // Timer callback
  private void OnTimerElapsed(Object progressReporter)
  {    
    //Get FFT Data
    int ret = BassWasapi.BASS_WASAPI_GetData(_fft, (int)BASSData.BASS_DATA_FFT8192);
    if (ret < -1) 
      return;

    List<double> values = new List<double>();

    double x, y;
    double b0 = 0;

    //Calculate FFT data to Frequency
    for (x = 0; x < _lines; x++)
    {
      float peak = 0;
      double b1 = Math.Pow(2, x * 10.0 / (_lines - 1));
      if (b1 > 1023) 
        b1 = 1023;

      if (b1 <= b0) 
        b1 = b0 + 1;

      for (; b0 < b1; b0++)
      {
        if (peak < _fft[1 + b0]) peak = _fft[1 + b0];
      }

      y = (Math.Sqrt(peak) * 3 * 255 - 4);
      if (y > 255) 
        y = 255;

      if (y < 0) 
        y = 0;

      values.Add(y);    
    }

    // Update the spectrum bars of the UI
    (progressReporter as IProgress<IEnumerable<double>>).Report(values);
  }
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <ListView x:Name="SpectrumBars"
            ItemsSource="{Binding SpectrumData}">

    <ListView.ItemTemplate>
      <DataTemplate DataType="system:Double">
        <ProgressBar Height="100"
                     Value="{Binding Path=., Mode=OneWay}"
                     Width="5"
                     Orientation="Vertical" />
      </DataTemplate>
    </ListView.ItemTemplate>

    <ListView.ItemsPanel>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal " />
      </ItemsPanelTemplate>
    </ListView.ItemsPanel>

    <ListView.ItemContainerStyle>
      <Style TargetType="ListBoxItem">
        <Setter Property="IsHitTestVisible"
                Value="False" />
        <Setter Property="VerticalContentAlignment"
                Value="Bottom" />
      </Style>
    </ListView.ItemContainerStyle>
  </ListView>
</Window>