当前位置:首页 > C#编程 > C#/.net框架 > 正文内容

C#4.0的并行库TPL,即Task(二)

Jorge2年前 (2022-05-09)C#/.net框架586


示例六:并行运行任务


程序启动后创建了两个task。然后用Task.WhenAll方法,创建了第三个Task,

该任务会在所得分任务完成后运行,该任务的结果是一个数组,元素1表示第一个任务结果,

第二个元素表示第二个任务的结果,以此类推。

后面用for循环创建了一系列任务,并使用Task.WhenAny方法等待这些任务中的任何一个完成。

当得分一个完成任务后,从列表中移除该任务并继续等待其它任务完成,直到列表为空。

获取任务完成情况或者判断运动中的任务是否超时,都可以用Task.WhenAny方法。

例如:一组任务判断超时,我们使用其中一个任务来记录是否超时,如果该任务先完成,则只需要取消掉其它还未完成的任务。


代码:

C#
using System;using System.Collections.Generic;using System.Threading;using System.Threading.Tasks;namespace Chapter4.Recipe8{
	class Program
	{
		static void Main(string[] args)
		{
			var firstTask = new Task<int>(() => TaskMethod("First Task", 3));
			var secondTask = new Task<int>(() => TaskMethod("Second Task", 2));
			var whenAllTask = Task.WhenAll(firstTask, secondTask);

			whenAllTask.ContinueWith(t =>
				Console.WriteLine("The first answer is {0}, the second is {1}", t.Result[0], t.Result[1]),
				TaskContinuationOptions.OnlyOnRanToCompletion				);

			firstTask.Start();
			secondTask.Start();

			Thread.Sleep(TimeSpan.FromSeconds(4));

			var tasks = new List<Task<int>>();
			for (int i = 1; i < 4; i++)
			{
				int counter = i;
				var task = new Task<int>(() => TaskMethod(string.Format("Task {0}", counter), counter));
				tasks.Add(task);
				task.Start();
			}

			while (tasks.Count > 0)
			{
				var completedTask = Task.WhenAny(tasks).Result;
				tasks.Remove(completedTask);
				Console.WriteLine("A task has been completed with result {0}.", completedTask.Result);
			}

			Thread.Sleep(TimeSpan.FromSeconds(1));
            Console.ReadKey();
		}

		static int TaskMethod(string name, int seconds)
		{
			Console.WriteLine("Task {0} is running on a thread id {1}. Is thread pool thread: {2}",
				name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
			Thread.Sleep(TimeSpan.FromSeconds(seconds));
			return 42 * seconds;
		}
	}}

image.png




示例七:TaskScheduler进行调度Task


程序启动后,有三个按钮。

第一按钮Sync调用一个同步任务的执行。这时候窗体卡住。


第二个按钮Async在另一个线程中访问UI(异步运行任务), 窗体是没有卡住,但是5秒钟后报一个错误。如图7.2所示。

这是因为ui被定义为不允许从UI线程之外的线程进行访问。

如果我们强行继续,会看到如图7.3的信息。

而之所以你可以看到继续输出的错误信息,是因为TaskScheduler.FromCurrentSynchronizationContext()这个方法。

它使TPL基础设施对UI的操作转到UI线程上去操作。


第三个按钮Async OK,依图7.4的结果,我们可以看到异步代码工作在线程Id为8的线程上面,它就是UI线程。


image.png

(图7.1)


image.png

(图7.2)


image.png

(图7.3)


image.png

(图7.4)



代码:


C#
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;using System.Windows.Forms;namespace WindowsFormsApplication5{
    public partial class Form1 : Form    {

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }



        Task<string> TaskMethod(TaskScheduler scheduler)
        {
            Task delay = Task.Delay(5000);

            return delay.ContinueWith(t =>
            {
                string str = string.Format("Task is running on a thread id {0}. Is thread pool thread: {1}",
                Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
                ContentTextBlock.Text = str;
                return str;
            }, scheduler);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ContentTextBlock.Text = string.Empty;
            try
            {
                string result = TaskMethod(TaskScheduler.Default).Result;
                ContentTextBlock.Text = result;
            }
            catch (Exception ex)
            {
                ContentTextBlock.Text = ex.InnerException.Message;
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {

            label3.Text =$"UI线程:{ Environment.CurrentManagedThreadId.ToString()}";
            label2.Text = string.Empty;
            // task 并没有运行在线程池中,而是 FromCurrentSynchronizationContext
            Task<string> task = TaskMethod(TaskScheduler.FromCurrentSynchronizationContext()); 
            task.ContinueWith(t =>
            {
                label2.Text = "hello!";
            },
            CancellationToken.None,
            TaskContinuationOptions.None,
            TaskScheduler.FromCurrentSynchronizationContext());
        }

        private void button2_Click(object sender, EventArgs e)
        {

            ContentTextBlock.Text = string.Empty;
            //这个函数主要就是这里用了default,所以用了线程池线程,而taskmethod里面有操作ui对象,因此出错!
            Task<string> task = TaskMethod(TaskScheduler.Default);
            task.ContinueWith(t =>
            {
                //这里的后续操作是在ui线程中做的,没有出错。
                ContentTextBlock.Text = t.Exception.InnerException.Message;
            },
            CancellationToken.None,
            TaskContinuationOptions.OnlyOnFaulted,  //onlyonfaulted,
            TaskScheduler.FromCurrentSynchronizationContext());

        }
    }}


最后来补充一个经典的死锁案例,将上例中的代码增加一行Result:


string s = task.Result; //这句话将让UI线程等待直到UI线程完成task中的内容,

但是等待中的UI线程没有办法操作,因此死锁!

C#
        private void button3_Click(object sender, EventArgs e)
        {

            label3.Text =$"UI线程:{ Environment.CurrentManagedThreadId.ToString()}";
            label2.Text = string.Empty;
            // task 并没有运行在线程池中,而是 FromCurrentSynchronizationContext
            Task<string> task = TaskMethod(TaskScheduler.FromCurrentSynchronizationContext());

            //这句话将让UI线程等待直到UI线程完成task中的内容,但是等待中的UI线程没有办法操作,因此死锁!
            string s = task.Result;
            task.ContinueWith(t =>
            {
                label2.Text = "hello!";
            },
            CancellationToken.None,
            TaskContinuationOptions.None,
            TaskScheduler.FromCurrentSynchronizationContext());
        }

为了避免死锁,绝对不要通过任务调度程序在UI线程中使用同步操作,请使用C# 5.0中的 ContinueWith或者async/await方法。

C#4.0的并行库TPL,即Task(一)http://www.skcircle.com/?id=1793

C#4.0的并行库TPL,即Task(二) http://www.skcircle.com/?id=1798

C#4.0的并行库TPL,即Task(三) http://www.skcircle.com/?id=1808

C#4.0的并行库TPL,即Task(四)  http://www.skcircle.com/?id=1815

C#4.0的并行库TPL,即Task(五) http://www.skcircle.com/?id=1816


--------------------- 

作者:hackpig
来源:
www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

扫描二维码推送至手机访问。

版权声明:本文由7点博客发布,如需转载请注明出处。

本文链接:http://6dot.cn/?id=92

标签: .NET.NET框架
分享给朋友:

“C#4.0的并行库TPL,即Task(二)” 的相关文章

windows下c#程序提高实时性

windows下c#程序提高实时性

引言:我们手里的运控软件对实时性有了新要求。因为同设备上运行的其它视觉软件对cpu时间有变态的占用,压缩了运控软件的cpu占用时间。我们知道如果视觉软件卡一下,最多是处理时间长一点,但是运控软件卡一下,那就意味着撞机的问题,这个要严重得多。这个问题会持续把研究结果更新到本贴子。(一)提升线程和进程的...

C#中使用RegisterWindowMessage进行进程之间进行通讯

C#中使用RegisterWindowMessage进行进程之间进行通讯

注:大家都知道在window里,进程之间通讯可以用消息通讯。但是有个较冷门的知识就是RegisterWindowMessage。一般的sendmessage和postmessage是需要在窗体程序间进行通讯,你得知道对方窗口的句柄。这个句柄每次启动程序时是系统分配的,每次不一样。有了这个Regist...

C#:多进程开发,控制进程数量

C#:多进程开发,控制进程数量

正在c#程序优化时,如果多线程效果不佳的情况下,也会使用多进程的方案,如下:C#System.Threading.Tasks.Task task=System.Threading.Tasks.Task.Factory.StartNew(     &...

c#——表达式树在LINQ动态查询

c#——表达式树在LINQ动态查询

一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件简单方式这样操作就可以了C#public IQueryable<FileImport> DynamicChainedSyntax (IQueryable<FileImport&g...

.NET(C#) TPL:Task中未觉察异常和TaskScheduler.UnobservedTaskException事件

.NET(C#) TPL:Task中未觉察异常和TaskScheduler.UnobservedTaskException事件

当你在一个Task执行中抛出异常,比如:C#Task.Factory.StartNew(() =>{    throw new Exception();});运行该方法,没有任何异常抛出。事实上此时Task的异常处于未觉察状...

细说进程、应用程序域与上下文之间的关系(三)—— 深入了解.NET上下文

细说进程、应用程序域与上下文之间的关系(三)—— 深入了解.NET上下文

目录一、进程的概念与作用二、应用程序域三、深入了解.NET上下文四、进程应用程序域与线程的关系三、深入了解.NET上下文3.1 .NET上下文的概念应用程序域是进程中承载程序集的逻辑分区,在应用程序域当中,存在更细粒度的用于承载.NET对象的实体,那就.NET上下文Context。所有的.NET对象...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。