什么时候使用Task.Delay和Thread.Sleep有很好的规则?
在过去的几天里,我测试了.net 4.5和c#5的新功能.
我喜欢它的新async/await功能.之前我曾使用BackgroundWorker通过响应式UI在后台处理更长的进程.
我的问题是:在拥有这些不错的新功能之后,我何时应该使用async/await和什么时候使用BackgroundWorker?两者的常见情况是什么?
c# backgroundworker task-parallel-library async-await .net-4.5
我想显示在外部库中执行的计算进度.
例如,如果我有一些计算方法,并且我想在我的Form类中使用它为100000个值,我可以写:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Caluculate(int i)
{
double pow = Math.Pow(i, i);
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Maximum = 100000;
progressBar1.Step = 1;
for(int j = 0; j < 100000; j++)
{
Caluculate(j);
progressBar1.PerformStep();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我应该在每次计算后执行步骤.但是,如果我在外部方法中执行所有100000计算,该怎么办?如果我不想让这个方法依赖于进度条,我什么时候应该"执行步骤"?例如,我可以写
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void CaluculateAll(System.Windows.Forms.ProgressBar progressBar)
{
progressBar.Maximum = 100000;
progressBar.Step = 1;
for(int j = 0; …Run Code Online (Sandbox Code Playgroud) 在WinForms中,如何从UI线程强制立即更新UI?
我正在做的大致是:
label.Text = "Please Wait..."
try
{
SomewhatLongRunningOperation();
}
catch(Exception e)
{
label.Text = "Error: " + e.Message;
return;
}
label.Text = "Success!";
Run Code Online (Sandbox Code Playgroud)
在操作之前,标签文本未设置为"Please Wait ...".
我使用另一个线程进行操作解决了这个问题,但它变得毛茸茸,我想简化代码.
我想在两条指令之间等待几秒钟,但没有阻止执行.
例如,Thread.Sleep(2000)它不好,因为它会阻止执行.
我的想法是,我调用一个方法,然后等待X秒(例如20)监听一个事件.在20秒结束时,我应该根据20秒内发生的事情进行一些操作.
TL; DR:运行任务中的死锁StaTaskScheduler.长版:
我使用的是StaTaskScheduler从ParallelExtensionsExtras中通过平行小组,举办由第三方提供的一些遗留STA COM对象.StaTaskScheduler实现细节的描述如下:
好消息是TPL的实现能够在MTA或STA线程上运行,并考虑到底层API的相关差异,如WaitHandle.WaitAll(当方法提供多个等待句柄时,它只支持MTA线程).
我认为这意味着TPL的阻塞部分将使用等待API来提供消息,例如CoWaitForMultipleHandles,以避免在STA线程上调用时出现死锁情况.
在我的情况下,我相信发生以下情况:进程内STA COM对象A调用进程外对象B,然后期望从B通过回调作为传出调用的一部分.
以简化形式:
var result = await Task.Factory.StartNew(() =>
{
// in-proc object A
var a = new A();
// out-of-proc object B
var b = new B();
// A calls B and B calls back A during the Method call
return a.Method(b);
}, CancellationToken.None, TaskCreationOptions.None, staTaskScheduler);
Run Code Online (Sandbox Code Playgroud)
问题是,a.Method(b)永远不会回来.据我所知,这是因为内部阻塞等待BlockingCollection<Task>不会引发消息,因此我对引用语句的假设可能是错误的.
EDITED相同的代码工作测试WinForms应用程序的UI线程上执行时(即,提供TaskScheduler.FromCurrentSynchronizationContext()的,而不是staTaskScheduler到Task.Factory.StartNew).
解决这个问题的正确方法是什么?我应该实现一个自定义同步上下文,它将显式地使用消息CoWaitForMultipleHandles …
简单的搜索DoEvents会带来很多结果,这些结果基本上会导致:
DoEvents是邪恶的.不要使用它.请改用线程.
一般引用的原因是:
但是一些值得注意的Win32功能,例如TrackPopupMenu并DoDragDrop 执行自己的消息处理以保持UI响应,就像这样DoEvents.
然而,这些问题似乎都没有遇到过这些问题(性能,再入等等).
他们是如何做到的呢?他们如何避免引用的问题DoEvents?(或者做他们?)
我正在寻找一种有效的方法来通知用户某个表单当前正在加载(或更新)它的UI,这将需要几秒钟.
这可能发生在初始加载或更新时.由于它非常密集并且修改ui控件,因此必须在ui线程上完成,因此阻止用户.
没有改变光标,我希望获得与ajax页面类似的效果,整个区域由半透明面板覆盖,中间有动画齿轮.
你有没有做过类似的事情?或者你知道我应该咨询的有趣网站吗?
非常感谢
[EDITED] 这似乎是 Framework的Application.DoEvents实现中的一个错误,我在这里报告过.在UI线程上恢复错误的同步上下文可能会严重影响像我这样的组件开发人员.赏金的目标是更多地关注这个问题,并奖励@MattSmith,他的答案帮助追踪它.
我负责通过COM互操作UserControl将基于.NET WinForms 的组件作为ActiveX暴露给传统的非托管应用程序.运行时要求是.NET 4.0 + Microsoft.Bcl.Async.
该组件被实例化并在应用程序的主要STA UI线程上使用.它的实现使用async/await,因此它期望在当前线程(即,WindowsFormsSynchronizationContext)上安装序列化同步上下文的实例.
通常,WindowsFormsSynchronizationContext设置为Application.Run,托管应用程序的消息循环运行的位置.当然,这不是非托管主机应用程序的情况,我无法控制它.当然,主机应用程序仍然有自己的经典Windows消息循环,因此序列化await延续回调应该不是问题.
但是,到目前为止我提出的解决方案都不是完美的,甚至都不能正常工作.这是一个人为的例子,其中Test方法由主机app调用:
Task testTask;
public void Test()
{
this.testTask = TestAsync();
}
async Task TestAsync()
{
Debug.Print("thread before await: {0}", Thread.CurrentThread.ManagedThreadId);
var ctx1 = SynchronizationContext.Current;
Debug.Print("ctx1: {0}", ctx1 != null? ctx1.GetType().Name: null);
if (!(ctx1 is WindowsFormsSynchronizationContext))
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());
var ctx2 = SynchronizationContext.Current;
Debug.Print("ctx2: …Run Code Online (Sandbox Code Playgroud) c# ×8
winforms ×4
async-await ×3
.net ×2
.net-4.5 ×1
asynchronous ×1
com ×1
com-interop ×1
doevents ×1
excel ×1
excel-vba ×1
progress-bar ×1
timer ×1
vba ×1
visual-c++ ×1
wait ×1
winapi ×1
windows ×1