C# 异步编程 并行编程

10 篇文章 1 订阅

目录

异步编程

1. Thread 

2. Task

3. async + await

并行编程

Parallel


本篇简单记录一下异步编程和并行编程,并以下图一个 Demo 来演示,源码地址我会公布在文章结尾。

  • 异步编程

个人觉得,异步无非就是不影响某个线程的情况下,在另外的线程里执行任务的过程。异步编程即多线程编程。C# 里多线程编程写法有很多种,这里记录三种。

  • 1. Thread 

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<EventWaitHandle>();
	waits.Add(e);
	WaitHandle.WaitAll(waits.ToArray());
	Console.WriteLine("After Wait");
}

 

  • 2. Task

Task 是 .net 4.0 才有的,严格的说,Task 不应该放在这里和 Thread 相提并论,因为它们压根不一样,什么意思?简单的说:

  • Thread仅仅是一条线程,所有操作都是这个 Thread 完成的;
  • Task 是将多个操作封装成一个概念上原子操作,但这个操作由哪个 Thread 甚至多个 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");
}

  • 3. async + await

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。

  • Parallel

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暂停示例 

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <TextBlock Margin="16" x:Name="CurrentTextValue" />
            <Button x:Name="PauseResume" Width="100" Height="40" Click="OnPauseResumeClick"></Button>
        </StackPanel>
    </Grid>
    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<int>(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;
        }
    }

源码: https://github.com/sudazf/TaskDemo.git

  • 6
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值