每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上优化此代码。
答案 0 :(得分:0)
我看不到任何使线程等待的原因,这对性能产生不必要的影响,尤其是在挂起的线程是UI线程时。只需将计时器配置为在预定义的时间间隔内调用回调即可。还优化您的UI,以启用绑定以更新光谱条。
此示例使用ListView
,其中StackPanel
的水平方向ItemsPanel
和ProgressBar
中定义的垂直方向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>