【发布时间】:2018-04-29 07:26:30
【问题描述】:
我有一个名为 ProxyTesterForm 的主窗体,它有一个子窗体 ProxyScraperForm。当 ProxyScraperForm 抓取新的代理时,ProxyTesterForm 通过异步测试抓取的代理来处理事件,并在测试后将代理添加到作为 DataGridView 的数据源的 BindingList。
因为我要添加到在 UI 线程上创建的数据绑定列表,所以我在 DataGridView 上调用 BeginInvoke,因此更新发生在适当的线程上。
在我将在下面发布的方法中没有 BeginInvoke 调用,我可以在处理过程中在屏幕上拖动表单,它不会卡顿并且很流畅。对于 BeginInvoke 调用,它的作用正好相反。
我对如何解决它有一些想法,但想在 SO 上听到比我更聪明的人的意见,所以我妥善解决了这个问题。
使用信号量 slim 来控制同时更新的数量。
将异步处理的项目添加到我将在下面发布的方法范围之外的列表中,并在 Timer_Tick 事件处理程序中迭代该列表,每 1 秒为列表中的每个项目调用 BeginInvoke,然后清除该列表并清洗,冲洗,重复直到工作完成。
放弃数据绑定的便利,转为虚拟模式。
-
其他人可能会在这里提出建议。
private void Site_ProxyScraped(object sender, Proxy proxy) { Task.Run(async () => { proxy.IsValid = await proxy.TestValidityAsync(judges[0]); proxiesDataGridView.BeginInvoke(new Action(() => { proxies.Add(proxy); })); }); }
【问题讨论】:
-
您是否考虑过使用取消令牌来防止多个同时请求?
-
@Stefan 不,我没有。这不是信号量的用途吗?我只使用了取消令牌来取消任务。
-
老实说,我认为您在这里不需要
Task.Run。而是将Site_ProxyScraped设为异步,因为我认为这是一个事件处理程序。然后 awaitproxy.TestValidtiyAsync和 BeginInvoke 可以保持原样。 -
考虑分层:它将帮助您克服这里的许多问题。例如,请参阅此(我自己的 XD)帖子; stackoverflow.com/questions/23648832/…
-
关键是将
proxy.IsValid = await proxy.TestValidityAsync(judges[0]);的结果存储在Dictionary或Collection中。它将非常快,并且不需要与 UI 交互。稍后您可以考虑更新 UI。也许有一个间隔为 500 毫秒的计时器或类似的东西。您将从Dictionary或Collection更新 UI
标签: c#