C#开发中关于Task后台进程的解读
demo
代码地址:https://gitee.com/chenheze90/L23_TaskAndThread
demo下载:https://gitee.com/chenheze90/L23_TaskAndThread/repository/archive/master.zip
前言
基本上,C#软件开发都会涉及线程的开发。线程是一个非常好的工具,C#早期用的最多的是Thread,现在建议大家用Task。本文主要介绍Task的功能。
async是否后台线程
理论上,是的,async方法就是后台线程。首先我们以正常代码为例,如下代码测试所示
static void Main(string[] args)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("当前线程的ID是:" + threadId);
TestthreadId();
Console.ReadLine();
}
private static void TestthreadId()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("方法中的线程的ID是:" + threadId);
}
在Main方法中执行一个正常的方法,我们可以看到两个的线程id是一致的
如果仅仅是在方法前增加async修饰,则会被当做同步方法来使用
运行的结果和第一份代码一致
但是如果加了异步方法,如 await Task.Delay(1000),则此方法就会变成异步方法,且线程id也会改变,如下代码所示
private static async void TestthreadId()
{
await Task.Delay(1000);
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("方法中的线程的ID是:" + threadId);
}
Main方法主线程的线程ID是1,而async方法的线程ID是4
以上实验证明,async修饰的方法是异步方法
async不为后台线程的特殊情况——winform、wpf
特殊:在wpf和winform中,async不是后台线程。
我们先用Thread做个示范
public Form1()
{
InitializeComponent();
}
int i = 0;
private void Form1_Load(object sender, EventArgs e)
{
Thread t = new Thread(AddNum);
t.Start();
}
private void AddNum()
{
while (true)
{
// 一定要用异步方法!!!!不然会报错
Invoke(new Action(() =>
{
textBox1.Text = (++i).ToString();
}));
Thread.Sleep(500);
}
}
在这里,我们用thread做了个线程,不断增加文本框的数字
用thread做线程,一切正常
我们接下来,我们把thread改成async方法,如下代码所示
int i = 0;
private void Form1_Load(object sender, EventArgs e)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("当前线程的ID是:" + threadId);
AddNum();
}
private async void AddNum()
{
await Task.Delay(3000);
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("方法中的线程的ID是:" + threadId);
while (true)
{
// 即使没有用Invoke方法,也能够操作UI控件,说明方法和主线程在同一个线程中,输出的线程ID也能证明这一点
textBox1.Text = (++i).ToString();
await Task.Delay(500);
}
}
可以看到,async中没有用Invoke
针对winform和wpf,在async方法中,即使没有用Invoke方法,也能够操作UI控件
这个是他特殊的地方
Task.Run到底有没有在异线程运行
有的,Task.Run确实在异步线程运行,代码如下
int i = 0;
private void Form1_Load(object sender, EventArgs e)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("当前线程的ID是:" + threadId);
Task.Run(() =>
{
Console.WriteLine("方法2中的线程的ID是:" + Thread.CurrentThread.ManagedThreadId);
// 一定要用异步方法!!!!
Invoke(new Action(() =>
{
textBox1.Text = "Task.Run测试";
}));
});
}
在输出界面,我们可以看到输出内容。Task.Run确实在异步线程运行
当前线程的ID是:1
方法2中的线程的ID是:4
后台线程控制前端UI的方法集锦
winform
this.Invoke((Action)(() => // this是WinForms窗体,或者其他任何控件都可以
{
// 在主线程中执行需要操作的UI代码
}));
this.BeginInvoke((Action)(() => // this是WinForms窗体,或者其他任何控件都可以
{
// 在主线程中执行需要操作的UI代码
}));
wpf
Application.Current.Dispatcher.Invoke(((Action)delegate ()
{
// 在主线程中执行需要操作的UI代码
}));
await Application.Current.Dispatcher.BeginInvoke(((Action)delegate ()
{
// 在主线程中执行需要操作的UI代码
}));