构建多线程应用程序2 Parallel 并行类:Parallel.ForEach()、Task异步操作类:Task.Factory.StartNew()、并行LINQ查询: AsParallel()

来源:互联网 发布:javascript功能 编辑:程序博客网 时间:2024/06/05 11:45

一、.NET平台下的并行编程

       .NET 4发布了一个全新的并行编程库,使用 System.Threading.Tasks 中的类型,可以构建细粒度,可扩展的并行代码,而不必直接与线程和线程池打交道。此外,你还可以使用强类型的LINQ查询(通过并行LINQ,即PLINQ)来分配工作。

 

二、Parallel 并行类的作用

        以并行的方式迭代数据集合(实现了IEnumerable<T>的对象)。

        Parallel 并行类支持两个主要的静态方法(Parallel.For()Parallel.ForEach())。

 

示例:使用foreach                   阻塞方式处理图像数据

            使用Parallel.ForEach  并行方式处理图像数据

 

效果:

代码:

using System.Threading.Tasks;
using System.Threading;
using System.IO;

 

按钮点击:

        private void ProcessFiles()        {            //返回目录(包含子目录),所有文件名。如:C:\Pictures\1.jpg            string[] files = Directory.GetFiles(@"C:\Pictures","*.jpg",SearchOption.AllDirectories);                        string newDir= @"C:\ModifiedPictures";            Directory.CreateDirectory(newDir);//创建目录            //阻塞方式处理图像数据            foreach(string currentFile in files)            {                string filename = Path.GetFileName(currentFile);//返回指定路径的文件名和扩展名。如:1.jpg                using (Bitmap bitmap = new Bitmap(currentFile))//根据图片地址,得到图片                {                    bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);//旋转图片                    bitmap.Save(Path.Combine(newDir, filename));//保存图片                    this.textBox1.Text = string.Format("Processing {0} on thread {1}", filename, Thread.CurrentThread.ManagedThreadId);                }            }            //并行方式处理图像数据            //Parallel.ForEach 循环files(currentFile中的项)            Parallel.ForEach(files, currentFile =>            {                string filename = Path.GetFileName(currentFile);//返回指定路径的文件名和扩展名。如:1.jpg                using (Bitmap bitmap = new Bitmap(currentFile))//根据图片地址,得到图片                {                    bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);//旋转图片                    bitmap.Save(Path.Combine(newDir, filename));//保存图片                    this.textBox1.Text = string.Format("Processing {0} on thread {1}", filename, Thread.CurrentThread.ManagedThreadId);                }            });            this.textBox1.Text = "完成!";        }


 

三、Task异步操作类

        Task 在次线程中调用方法
        Task的Factory属性返回一个TaskFactory对象。
        调用StartNew()方法时,传入一个Action<T>委托(这里为一个Lambda表达式),指向以异步方式进行调用的方法。

 

           Task.Factory.StartNew(() => {
                调用的方法           
           }); 

 

代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading.Tasks;using System.Threading;using System.IO;namespace WindowsFormsApplication1{    public partial class Form1 : Form    {        public Form1()        {            Control.CheckForIllegalCrossThreadCalls = false;//是否进行控件操作线程的检查            //1.在窗体构造函数中写Control.CheckForIllegalCrossThreadCalls =false;            //2.使用Invoke等委托函数。问题原因是。            //net2.0以后拒绝多线程访问空间,避免空间造成死锁。            //以前Control.CheckForIllegalCrossThreadCalls =false;默认就是这样,现在默认为true。            //如果不会好几个线程同时操作一个控件用方法1就可以。            //如果存在多个线程一起操作控件使用方法2            //    方法2可以Invoke(new MethodInvoker(delegate(){//do something... }));            InitializeComponent();        }        private void btnProessImages_Click(object sender, EventArgs e)        {            //Task 在次线程中调用方法            //Task的Factory属性返回一个TaskFactory对象。            //调用StartNew()方法时,传入一个Action<T>委托(这里为一个Lambda表达式),指向以异步方式进行调用的方法。            Task.Factory.StartNew(() => {                ProcessFiles();            });             }        private void ProcessFiles()        {            //返回目录(包含子目录),所有文件名。如:C:\Pictures\1.jpg            string[] files = Directory.GetFiles(@"C:\Pictures","*.jpg",SearchOption.AllDirectories);                        string newDir= @"C:\ModifiedPictures";            Directory.CreateDirectory(newDir);//创建目录            //阻塞方式处理图像数据            foreach(string currentFile in files)            {                string filename = Path.GetFileName(currentFile);//返回指定路径的文件名和扩展名。如:1.jpg                using (Bitmap bitmap = new Bitmap(currentFile))//根据图片地址,得到图片                {                    bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);//旋转图片                    bitmap.Save(Path.Combine(newDir, filename));//保存图片                    this.textBox1.Text = string.Format("Processing {0} on thread {1}", filename, Thread.CurrentThread.ManagedThreadId);                }            }            this.textBox1.Text = "完成!";        }    }}


4.5框架,支持 Task.Run()。是把 await 之后的内容包装起来放到新的线程环境去执行


async必须加在函数声明处,如果不加async关键字,函数内部不能使用await关键字,仅仅如此

await只能用来等待一个Task或者Task<T>进行异步执行返回

实例1:

//异步方法        public async Task<int> MethodA(DateTime bgtime, int i)        {            int r = await Task.Run(() =>            {                Console.WriteLine("异步方法{0}Task被执行", i);                Thread.Sleep(100);                return i * 2;            });            Console.WriteLine("异步方法{0}执行完毕,结果{1}", i, r);            if (i == 49)            {                Console.WriteLine("用时{0}", (DateTime.Now - bgtime).TotalMilliseconds);            }            return r;        }

 调用:

       public static void ACTest()

        {
            Asy_ClassA asy = new Asy_ClassA();


            DateTime abgtime = DateTime.Now;
            for (int i = 0; i < 50; i++)
            {
                asy.MethodA(abgtime, i);
                Console.WriteLine("异步方法{0}调用完成", i);
            }
        }



实例2:

    class Program    {        private static async void Test()        {            Task<int> t = new Task<int>(() => { Thread.Sleep(3000); return 1; });            t.Start();            int tr = await t;            Console.WriteLine(tr);        }        static void Main(string[] args)        {            Test();            Console.WriteLine("Main");            Console.ReadKey();        }    }



四、并行LINQ查询(PLINQ)

       System.Linq命名空间的ParallelEnumerable

        1、AsParallel() 启用查询并行化
        2、WithCancellation()  指示PLINQ应定时监视取消标记状态

 

截面:

代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Threading.Tasks;using System.Threading;using System.IO;namespace WindowsFormsApplication1{    public partial class Form1 : Form    {        private CancellationTokenSource cancelToken = new CancellationTokenSource();//取消标记        public Form1()        {            InitializeComponent();        }        private void btnExecute_Click(object sender, EventArgs e)        {            ProcessIntData();                  }        private void btnCancle_Click(object sender, EventArgs e)        {            cancelToken.Cancel();//取消        }        private void ProcessIntData()        {            //获得很大的整数数组            int[] source = Enumerable.Range(1, 10000000).ToArray();                    //找到num%3==0为True 的数字,降序返回            int[] modThreeIsZero = null;            try            {                //AsParallel()启用查询并行化                //WithCancellation() 指示PLINQ应定时监视取消标记状态                modThreeIsZero = (from num in                                      source.AsParallel().WithCancellation(cancelToken.Token)                                  where num % 3 == 0                                  orderby num descending                                  select num).ToArray();            }            catch (OperationCanceledException ex)            {                this.textBox1.Text = ex.Message;            }            MessageBox.Show(string.Format("发现{0}个数", modThreeIsZero.Count()));        }    }}


 

 

0 0
原创粉丝点击