C# Parallel.For和Parallel.ForEach学习

来源:互联网 发布:算工资的软件 编辑:程序博客网 时间:2024/05/21 06:27

《精通C#编程(第6版)》598页,“在次线程中访问UI元素”,按照书上的源代码程序总是无响应,百度后发现是线程死锁的原因;

参见  

c#+Parallel.ForEach的卡死现象

使用了ThreadPool.QueueUserWorkItem改进书上例子。

3a.如果单个任务执行非常快以致于创建线程的开销远大于在当前线程执行剩余任务的开销,那么任务调度器不会创建其它工作线程,所有的Invoke都在当前线程得以执行,ForEach返回。
3b.如果创建线程可能加快任务处理速度,任务调度器会创建工作线程,并在工作线程上安排任务。
4b.在工作线程上执行的Invoke全部被阻塞,等待窗体线程进行处理。
5b.窗体线程执行所有可执行的任务后,等待ForEach返回,但由于其他线程在等待窗体线程处理Invoke,任务不能完成,ForEach无法返回,造成死锁。


public partial class MainForm : Form    {        public MainForm()        {            InitializeComponent();        }        private void btnProcessImage_Click(object sender, EventArgs e)        {            DirectoryInfo dir = new DirectoryInfo(@"d:\samplePicture");            dir.Delete(true);            dir = new DirectoryInfo(@"d:\samplePictureParallelForEach");            dir.Delete(true);            dir = new DirectoryInfo(@"d:\samplePictureParallelFor");            dir.Delete(true);                        ThreadPool.QueueUserWorkItem(w =>            {                ProcessImage();             }, null);                        ThreadPool.QueueUserWorkItem(w =>            {                ProcessImageParallelFor();            }, null);            ThreadPool.QueueUserWorkItem(w =>            {                ProcessImageParallelForEach();            }, null);            textBox1.AppendText("\r\n");                    }                private void ProcessImage()        {            Stopwatch sw = new Stopwatch();            sw.Start();            string[] files = Directory.GetFiles(@"d:\sample", "*.jpg", SearchOption.AllDirectories);            string newDir = @"d:\samplePicture";            Directory.CreateDirectory(newDir);                        foreach(string currentfile in files)            {                string fileName = Path.GetFileName(currentfile);                using (Bitmap bitMap = new Bitmap(currentfile))                {                    bitMap.RotateFlip(RotateFlipType.Rotate180FlipNone);                    bitMap.Save(Path.Combine(newDir, fileName));                    Invoke((Action)delegate                    {                        Text = string.Format("Processing {0} on thread {1}", fileName, Thread.CurrentThread.ManagedThreadId);                    });                }            }            sw.Stop();            Invoke((Action)delegate            {                textBox1.AppendText(string.Format("\r\n正常Foreach循环耗时:{0} ", sw.Elapsed.TotalSeconds.ToString()));            });                                }        //ParallelForEach 并行        private void ProcessImageParallelForEach()        {            Stopwatch sw2 = new Stopwatch();            sw2.Start();            string[] files = Directory.GetFiles(@"d:\sample", "*.jpg", SearchOption.AllDirectories);            string newDir = @"d:\samplePictureParallelForEach";            Directory.CreateDirectory(newDir);            Parallel.ForEach            (files, currentfile =>                {                    string fileName = Path.GetFileName(currentfile);                    using (Bitmap bitMap = new Bitmap(currentfile))                    {                        bitMap.RotateFlip(RotateFlipType.Rotate180FlipNone);                        bitMap.Save(Path.Combine(newDir, fileName));                        Invoke((Action)delegate                        {                            Text = string.Format("Processing {0} on thread {1}",                                fileName, Thread.CurrentThread.ManagedThreadId);                        });                    }                }            );            sw2.Stop();            Invoke((Action)delegate            {                textBox1.AppendText(string.Format("\r\n并行ForEach模式耗时:{0} ",                      sw2.Elapsed.TotalSeconds.ToString()));            });                    }        //ParallelFor并行        private void ProcessImageParallelFor()        {            Stopwatch sw3 = new Stopwatch();            sw3.Start();            string[] files = Directory.GetFiles(@"d:\sample", "*.jpg", SearchOption.AllDirectories);            string newDir = @"d:\samplePictureParallelFor";            Directory.CreateDirectory(newDir);                        Parallel.For(0, files.Length, (index) =>            {                string[] filesTemp = Directory.GetFiles(@"d:\sample", "*.jpg", SearchOption.AllDirectories);                string fileName = Path.GetFileName( filesTemp[index]);                using (Bitmap bitMap = new Bitmap(filesTemp[index]))                {                    bitMap.RotateFlip(RotateFlipType.Rotate180FlipNone);                    bitMap.Save(Path.Combine(newDir, fileName));                    Invoke((Action)delegate                    {                        Text = string.Format("Processing {0} on thread {1}", fileName, Thread.CurrentThread.ManagedThreadId);                    });                }            });            sw3.Stop();            Invoke((Action)delegate            {                textBox1.AppendText(string.Format("\r\n并行For模式耗时:{0} ",                     sw3.Elapsed.TotalSeconds.ToString()));            });                    }    }



测试结果: