目录
异步编程
1. Thread
2. Task
3. async + await
并行编程
Parallel
本篇简单记录一下异步编程和并行编程,并以下图一个 Demo 来演示,源码地址我会公布在文章结尾。
个人觉得,异步无非就是不影响某个线程的情况下,在另外的线程里执行任务的过程。异步编程即多线程编程。C# 里多线程编程写法有很多种,这里记录三种。
Thread 算是比较常用的写法,出来时间也比较早,一般分带参数和不带参数两种写法:
Thread thread1 = new Thread(new ThreadStart(ThreadMethod1));//不带参数
thread1.Start();
Thread thread2 = new Thread(new ParameterizedThreadStart(ThreadMethod2));//带参数
thread2.Start(para);
某些时候,不能任由线程各自运行,比如需要等待所有线程结束后再去做某件事,这个时候就需要线程同步,同步方式有很多种,并不是本文重点,感兴趣的请自行百度。这里介绍一种事件等待方式,而这种方式就可以用到带参数的线程写法:
static void Main(string[] args)
{
TestThread();
}
private static void TestThread()
{
ManualResetEvent resetEvent = new ManualResetEvent(false);
Thread thread1 = new Thread(new ParameterizedThreadStart(StartByThread));
thread1.Start(resetEvent);
WaitThread(resetEvent);
}
private static void StartByThread(object para)
{
ManualResetEvent mre= (ManualResetEvent)para;
for (int i = 1; i < 5; i++)
{
Console.WriteLine("Execute "+i.ToString());
Thread.Sleep(1000);
}
mre.Set();
}
private static void WaitThread(ManualResetEvent e)
{
var waits = new List();
waits.Add(e);
WaitHandle.WaitAll(waits.ToArray());
Console.WriteLine("After Wait");
}
Task 是 .net 4.0 才有的,严格的说,Task 不应该放在这里和 Thread 相提并论,因为它们压根不一样,什么意思?简单的说:
Task 应该和 Thread pool 比较合适,因为他们是处理一类任务的。在thread pool时期,我们不能知道一个workitem是否完成,也不能在完成后知道workitem所得出的返回值,task就是封装后解决这个问题的。当然这个只是小方面。Task还优化了thread pool的调用机制,在多核的情况下可以得到更好的效率。
下面介绍 Task 写法:
Task.Factory.StartNew(() => { });//方式1
Task task = new Task(()=> { });//方式2
task.Start();
当然还有很多种重载写法,具体请自行查阅。
同样,Task 也有等待方法 :
static void Main(string[] args)
{
TestTask();
}
private static void TestTask()
{
Task task1 = new Task(() => {
Console.WriteLine("Task1 executed");
Thread.Sleep(1000);
});
Task task2 = new Task(() => {
Console.WriteLine("Task2 executed");
Thread.Sleep(2000);
});
task1.Start();
task2.Start();
Wait(task1, task2);
}
private static void Wait(params Task[] tasks)
{
Task.WaitAll(tasks);
Console.WriteLine("Wait End");
}
async 和 await 是 .net 4.5才有的,它提供了更简洁的异步编程写法:
static void Main(string[] args)
{
TestAync();
Console.WriteLine("Test End");
Thread.Sleep(2000);
}
private static async void TestAync()
{
await Task.Run(()=> {
Console.WriteLine("Task Run 1");
Thread.Sleep(1000);
Console.WriteLine("Task Run 2");
});
}
async 方法中,也可以等待其它 Task , 但是不能用WaitAll, 只能用WhenAll, 否则可能会卡住当前线程,比如:
static void Main(string[] args)
{
TestAync();
Thread.Sleep(3000);
}
private static async void TestAync()
{
Task task1=new Task(()=> {
Console.WriteLine("Task Run 1");
Thread.Sleep(1000);
});
Task task2 = new Task(() => {
Console.WriteLine("Task Run 2");
Thread.Sleep(2000);
});
task1.Start();
task2.Start();
await Task.WhenAll(task1, task2);
Console.WriteLine("After when all");
}
其它用法请参考另一篇 Async+await 用法
异步编程中,线程之间只要互不影响,考虑同步问题即可。而在并行编程中,则要求多个线程在同一时刻同时运行。必须要有多核cpu。
C#中提供了 Parallel 相关方式来支持并行编程, 举个例子:
static void Main(string[] args)
{
Parallel.For(0, 5, (i) => {
Console.WriteLine("Step "+i.ToString());
});
}
而我们平常用的 for 循环,则不是并行的:
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Step " + i.ToString());
}
}
控制台程序并不能很好的展示并行与异步,这里使用一个桌面多线程示例来演示:
1.只使用异步,并没有使用并行:
2.使用异步+并行:
想要并行,只能使用 Thread, 使用 Task似乎达不到并行效果 。
补充:Task暂停示例
public partial class MainWindow : Window
{
private ManualResetEvent _resetEvent;
private bool _isPaused;
public MainWindow()
{
InitializeComponent();
this.PauseResume.Content = "Pause";
Start();
}
private void Start()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
_resetEvent = new ManualResetEvent(true);
Task task = new Task(async () =>
{
int i = 0;
while (true)
{
if (token.IsCancellationRequested)
{
return;
}
_resetEvent.WaitOne();
await Application.Current.Dispatcher.BeginInvoke(new Action(ShowResult), i++);
await Task.Delay(1000);
}
}, token);
task.Start();
}
private void ShowResult(int val)
{
this.CurrentTextValue.Text = val.ToString();
}
private void OnPauseResumeClick(object sender, RoutedEventArgs e)
{
if (_isPaused)
{
_resetEvent.Set();
this.PauseResume.Content = "Pause";
}
else
{
_resetEvent.Reset();
this.PauseResume.Content = "Resume";
}
_isPaused = !_isPaused;
}
}
Demo源码