我开发了一个小客户端(WPF)来对我们的系统进行压力测试。基本上,它必须并行调用Asp.Net WebApi端点上的各种方法。
每次按"开始"它与压力请求并行生成4000个任务(Async - Await),等待它们全部完成,然后再次执行 - 直到用户单击停止按钮。 GUI使用进度条和一些计数器进行装饰:错误请求,已完成请求,进度请求。我获取这些信息是因为使批量压力请求的对象暴露了一些事件:
var stressTestTask = new stressTestTask(LogService, configuration);
stressTestTask.ErrorRequestCountChanged += stressTestTask_ErrorRequestCountChanged;
stressTestTask.GoodRequestCountChanged += stressTestTask_GoodRequestCountChanged;
stressTestTask.TryRequestCountChanged += stressTestTask_TryRequestCountChanged;
_executionCancellationToken = new CancellationTokenSource();
await Task.Run(
() => stressTestTask.ApiStressTestTask(_executionCancellationToken.Token),
_executionCancellationToken.Token);
整个执行从ICommand
(MVVM):
private RelayCommand _startCommand;
public RelayCommand StartCommand
{
get
{
return _startCommand ?? (_startCommand = new RelayCommand(
async () =>
{
await StartStressTest();
}));
}
}
RelayCommand
是来自库ICommand
的{{1}}的实现。
我不明白这种行为:如果我使用" low"来配置我的批量任务。任务数量,例如2000,GUI在执行时不会冻结。相反,如果我选择了5000个任务,过了一会儿它会冻结。如果那时我打开了我的客户端的.exe的另一个实例,并且每个都选择了2000,那么GUI在两者中都是响应的。
我的第一个问题是:为什么使用Mvvm-Light
任务打开一个实例在响应性方面比使用x
任务打开n
个实例更糟糕?它是否与Windows Scheduler有关,而且在第一种情况下我只有一个进程?
我的第二个问题是:如何解决问题以使所有内容在单个GUI上运行?我想过用一批压力测试制作一个控制台应用程序,并为我想要的每个实例从GUI调用一个命令,以便为每个批处理生成一个进程。
答案 0 :(得分:1)
您是否通过调用UI上下文来处理这些API事件?如果您发生了许多调用,您将使调度程序充满操作并导致UI挂起并滞后于用户输入。
尝试批量处理UI更新。
答案 1 :(得分:1)
我的第一个问题是:为什么用x任务打开一个实例在响应性方面比用x / n任务打开n个实例更糟糕?
可能是因为您要在UI线程上处理更多事件。我想你的UI线程上调用了你的ErrorBetCountChanged,GoodRequestCountChanged和TryRequestCountChanged事件处理程序,并且引发的很多事件可能会泛滥UI线程。
正如Gusdor所说,你应该找到一种批量更新的方法。看一下反应性扩展(Rx):http://www.introtorx.com/content/v1.0.10621.0/01_WhyRx.html。
它有一个可以派上用场的缓冲区方法:http://www.introtorx.com/content/v1.0.10621.0/13_TimeShiftedSequences.html。
它还具有可用于将事件转换为IObservable的Obervable.FromEvent方法:https://msdn.microsoft.com/en-us/library/hh229241(v=vs.103).aspx。
我的第二个问题是:如何解决问题,使一切工作在一个GUI上?
您需要找到一种方法 - 一个或另一个 - 更频繁地更新UI。批处理更新和事件应该是一个很好的起点。提高通知率是另一种选择。也许你需要两者。
答案 2 :(得分:0)
如何解决问题,使一切工作在一个GUI上?
发送API请求"正确" async-await方式只有一个线程。
private async Task SendStressRequests()
{
var tasks = new List<Task>();
for (int i = 0; i < 4000; i++)
{
var task = SendApiRequestAsync();
tasks.Add(task);
}
await Task.WhenAll(tasks);
// Update UI with results
}