带有线程计时器的Async /await
本文关键字:Async await 计时器 线程 | 更新日期: 2023-09-27 18:06:54
我能够解决输入表单Stephen Cleary的问题。
我有一个Windows窗体应用程序,它有一个带有异步修饰符的方法。如果该方法在按钮的点击事件中被调用,它不会阻塞UI线程。然而,当我在计时器内调用它作为回调时,它会冻结UI。我不知道我做错了什么。请参阅下面我的代码。这只是一个用于演示的示例项目。
public Form1()
{
InitializeComponent();
}
private async void formCloseAsync()
{
shutdown stf = new shutdown();
stf.StartPosition = FormStartPosition.CenterScreen;
stf.Show();
var task = Task.Factory.StartNew(processClose);
await task;
}
private void processClose()
{
Thread.Sleep(5000);
Environment.Exit(1);
}
private void simpleButtonAsync_Click(object sender, EventArgs e)
{
formCloseAsync();
}
private void _simpleButtonTimer_Click(object sender, EventArgs e)
{
Timer _shutdownTimer = new Timer(delegate
{
formCloseAsync();
}, null, 5000, Timeout.Infinite);
}
更新1:谢谢大家的宝贵意见。请参阅下面的更新代码
public Form1()
{
InitializeComponent();
}
private Timer _shutdownTimer;
private void formCloseAsync()
{
shutdown stf = new shutdown();
stf.StartPosition = FormStartPosition.CenterScreen;
stf.Show();
Task.Run(async ()=>
{
await Task.Delay(5000);
Environment.Exit(1);
}
);
}
private void simpleButtonAsync_Click(object sender, EventArgs e)
{
formCloseAsync();
}
private void _simpleButtonTimer_Click(object sender, EventArgs e)
{
_shutdownTimer = new Timer(async delegate
{
formCloseAsync();
}, null, 0, Timeout.Infinite);
}
然而,我仍然有同样的问题。在计时器回调内部调用Shutdown STF时被阻塞。主UI是可以的。这没有问题。我只是想关机(stf) GUI是响应时,从计时器回调创建。关机GUI有一个进度条。
更新3:
这是最后的代码
public partial class Form1 : Form
{
readonly shutdown _stf = new shutdown();
public Form1()
{
InitializeComponent();
}
private Timer _shutdownTimer;
private async Task formCloseAsync()
{
try
{
BeginInvoke(new MethodInvoker(delegate
{
_stf.StartPosition = FormStartPosition.CenterScreen;
_stf.Show();
}));
await Task.Run( async () =>
{
await Task.Delay(5000);
});
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
Environment.Exit(1);
}
}
private void simpleButtonAsync_Click(object sender, EventArgs e)
{
formCloseAsync();
}
private void _simpleButtonTimer_Click(object sender, EventArgs e)
{
_shutdownTimer = new Timer(async delegate
{
formCloseAsync();
}, null, 0, Timeout.Infinite);
}
private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
await formCloseAsync();
}
用Task.Delay
代替:
await Task.Delay(5000);
由于Thread.Sleep
实际上阻塞了当前线程,因此不应该在异步方法中使用。
你可以在这里找到更多的信息:何时使用任务。延迟,何时使用Thread.Sleep?
但是,当我在计时器内调用它作为回调时,它会冻结UI。
你不能从后台线程访问UI元素(我猜stf.Show();
正在显示一个对话框)。最简单的修复方法可能是将System.Threading.Timer
替换为Windows.Forms.Timer
。
其他笔记:
- 你不应该使用
StartNew
;使用Task.Run
代替。请看我的博客文章StartNew
是危险的。 - 除了事件处理程序之外,你不应该使用
async void
。请参阅我的MSDN文章异步编程的最佳实践。