我最近决定看一下C#5的新async / await功能。出于演示目的,我编写了一个Windows窗体应用程序,允许用户获取整数数组并使用他们选择的排序例程对它们进行排序。与程序一起,我提供了五个测试.dat文件,每个文件包含从32,000个整数开始的未排序数据,每个后续文件的大小加倍。程序将文件中的数据读入一个准备排序的int数组。
我遇到的问题是GUI冻结并变得完全没有响应。但是,只有在GUI本身放置在后台时才会冻结。即,我看不到它,因为我可能正在忙着浏览互联网等。它可能不会立即冻结。有时候我可能会把它重新放回焦点但它仍然有效,但最终它会失败。如果我始终保持程序焦点,GUI将保持完全响应。我可以将它拖过屏幕。我可以最小化并最大化它。一个选框样式进度条动画,我可以在结果表单显示已用的排序时间之前继续单击按钮等。
现在我想补充一点,我不认为这是排序算法本身的问题。我的理由是,当GUI保持关注时,它工作正常。我还有一整套单元测试,验证每个算法是否正常工作。经过的时间似乎是一个问题,因为更快的算法(如堆或快速排序)可以处理非常大的数据集而不会导致冻结。最后,我尝试在表单级别(我等待任务)和任务本身内捕获异常,但似乎没有异常抛出异常。
在过去的两天里,我只是看了async / await,我绝不是专家,但我最初的想法是,它可能与重新获得焦点时重新关联。有人可以帮忙吗?以下是协助的代码部分: -
示例SelectionSort例程: -
public SelectionSort(IStopwatch stopwatch) : base(stopwatch){}
public override async Task<int[]> SortAsync(int[] data, CancellationToken cancelToken)
{
OnStarted();
Stopwatch.Start();
await Task.Run(() =>
{
int i, j;
int min, temp;
for (i = 0; i < data.Length - 1; i++)
{
if (cancelToken.IsCancellationRequested)
return;
min = i;
for (j = i + 1; j < data.Length; j++)
{
if (data[j] < data[min])
min = j;
}
temp = data[i];
data[i] = data[min];
data[min] = temp;
}
}, cancelToken);
Stopwatch.Stop();
OnCompleted(new SortCompleteEventArgs(Stopwatch.ElapsedMilliseconds, data.Length, cancelToken.IsCancellationRequested));
return data;
}
处理每个排序例程的分拣程序上下文(策略模式): -
public class SorterContext
{
private readonly SortRoutine _sortRoutine;
public SorterContext(SortRoutine sortRoutine)
{
_sortRoutine = sortRoutine;
}
public async Task<int[]> Sort(int[] dataToSort, CancellationToken cancellationToken)
{
if(dataToSort == null)
throw new ArgumentNullException("dataToSort");
if(dataToSort.Length == 1)
throw new ArgumentOutOfRangeException("dataToSort");
int[] result = await _sortRoutine.SortAsync(dataToSort, cancellationToken);
return result;
}
来自Windows窗体Click事件处理程序的调用: -
private async void StartSorting_Click(object sender, EventArgs e)
{
if (_lBoxSelectedFiles.Items.Count == 0)
{
MessageBox.Show("Select data to sort");
return;
}
_btnCancelSort.Enabled = true;
if (_comboBxAlgorithm.SelectedValue.Equals("SelectSort"))
{
var selectSort = new SelectSort(new SortStopwatch());
selectSort.Completed += DisplaySortResults;
_sorter = new SorterContext(selectSort);
StartProgressBar();
await _sorter.Sort(_dataToSort, _cancelTokenSrcWrapper.Token);
}
答案 0 :(得分:0)
异步代码似乎没有任何问题。在排序后引发OnComplete事件时,主窗体中的处理程序将实例化一个新的结果表单并显示它。当表格失焦时,这种情况就失败了。我正在调查为什么会出现这种情况,如果这是一个深思熟虑的框架设计决策。无论如何,我只是从处理程序中调用方法Activate()。这使应用程序成为焦点,然后我实例化了新的表单,它工作正常。它至少无论如何都会对我有用。例如: -
private void DisplaySortResults(object sender, SortCompleteEventArgs e)
{
Activate();
_btnCancelSort.Enabled = false;
_progressBar.Style = ProgressBarStyle.Continuous;
var sortResults = new SortResults();
sortResults.BuildResults(e);
sortResults.SetCompletedValues(e);
sortResults.ShowDialog();
}