zoukankan      html  css  js  c++  java
  • 线程

    Thread

    //开启线程, 构造函数参数可以是委托,可以是方法名, 可以是ThreadStart(不带参数),ParameterizedThreadStart(可以在start内传入object类型参数) 类型委托
    //Thread th = new Thread(()=> { });
    Thread thWithoutParam = new Thread(new ThreadStart(() => { }));
    Thread thWithParam = new Thread(new ParameterizedThreadStart((t) => { Thread.Sleep(10000); }));
    thWithoutParam.IsBackground = true;
    //后台线程在程序关闭时,可以不用等待后台线程执行完毕,前台线程需要等待线程执行完毕才能关闭
    thWithoutParam.Start();
    thWithParam.Start(new object());
    
    //可以让线程进入等待, 参数可以是TimeSpan 或者是 millisecondsTimeout 的整毫秒数
    thWithParam.Join();
    //释放线程
    thWithParam.Abort();
    
    /*
    * 注意:
    *  如果使用 Application.Exit() 退出程序时 会等待前台线程执行完才关闭程序
    *  Environment.Exit(0) 可以直接关闭,而不等待前台线程
    */
    View Code

    ThreadPool

    /*
     * 线程池 对于 Thread 的优点: 在频繁创建线程的时候,效率高. 把线程的开启与销毁交给系统,它会尽可能的用最优去管理
     */
    
    for (int i = 0; i < 10; i++)
    {
        //ThreadPool.QueueUserWorkItem(new WaitCallback(x => { }));//可以简写为
        ThreadPool.QueueUserWorkItem(x =>
        {
            ConsoleUtils.PrintLine(x + "========线程ID:" + Thread.CurrentThread.ManagedThreadId + "   开始执行");
            Thread.Sleep(5000);
            ConsoleUtils.PrintLine(x + "========线程ID:" + Thread.CurrentThread.ManagedThreadId + "   执行完成");
        }, i);//可以传入一个object 参数, 委托参数接收
    }
    View Code

    Task

    /*
        * Thread:
        *  当我们提及多线程的时候会想到thread和threadpool,这都是异步操作,
        *  threadpool其实就是thread的集合,具有很多优势,不过在任务多的时候全局队列会存在竞争而消耗资源。
        *  thread默认为前台线程,主程序必须等线程跑完才会关闭,而threadpool相反。
        *  
        * Task:
        *   task简单地看就是任务,那和thread有什么区别呢?
        *   Task的背后的实现也是使用了线程池线程,但它的性能优于ThreadPoll,
        *   因为它使用的不是线程池的全局队列,而是使用的本地队列,
        *   使线程之间的资源竞争减少。同时Task提供了丰富的API来管理线程、控制。
        *   但是相对前面的两种耗内存,Task依赖于CPU对于多核的CPU性能远超前两者,
        *   单核的CPU三者的性能没什么差别
        */
                 
    ConsoleUtils.PrintLine("main thread start.." + Thread.CurrentThread.ManagedThreadId);
    //开启一个线程 执行 返回类型是 Task<T>
    var task = Task.Run(() =>
    {
        ConsoleUtils.PrintLine("task execuete:" + Thread.CurrentThread.ManagedThreadId, ConsoleType.Warn);
        Thread.Sleep(5000);
        ConsoleUtils.PrintLine("task execuete after 5 secondes:" + Thread.CurrentThread.ManagedThreadId, ConsoleType.Warn);
    });
    //使用这个task对象, 在上面线程执行完成后, 开启线程执行 continueWith  中的代码
    task.ContinueWith(x => ConsoleUtils.PrintLine("execute in continue with:" + Thread.CurrentThread.ManagedThreadId));
    
    ConsoleUtils.PrintLine("main thread end.." + Thread.CurrentThread.ManagedThreadId);
    //---------------------------------------任务等待----------------------------------------------------------
    //开启一个任务 定义一个任务对象,
    Task testTask = new Task(() =>
    {
        Console.WriteLine("task start");
        System.Threading.Thread.Sleep(2000);
    });
    //任务开始
    testTask.Start();
    var factoryTeak = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("factory task start");
    });
    //等待多个任务完成, 多线程中的异常可以在此处被捕获
    Task.WaitAll(testTask, factoryTeak);
    //等待任意一个任务完成,就执行下面代码
    Task.WaitAny(testTask, factoryTeak);
    
    Console.WriteLine("end");
    
    
    var singleTask = new Task(() =>
    {
        Console.WriteLine("task start");
        System.Threading.Thread.Sleep(2000);
    });
    singleTask.Start();
    //单个任务进行等待
    singleTask.Wait();
    Console.WriteLine("end");
    
    //------------------任务取消-------------------------
    var tokenSource = new CancellationTokenSource();//创建取消task实例
    var cancelTask = new Task(() =>
    {
        for (int i = 0; i < 6; i++)
        {
            Console.WriteLine("hello:" + i);
            System.Threading.Thread.Sleep(1000);
        }
    }, tokenSource.Token);
    //Console.WriteLine(testTask.Status);
    //如果任务已经开始执行,将不能被取消
    //testTask.Start();
    Console.WriteLine(cancelTask.Status);
    //取消时执行的回调函数
    tokenSource.Token.Register(() => {
        Console.WriteLine("task is to cancel");
    });
    tokenSource.Cancel();
    Console.WriteLine(cancelTask.Status);
    
    //---------------父子task------------
    var parentTask = new Task(() =>
    {
        var childTask = new Task(() =>
        {
            System.Threading.Thread.Sleep(2000);
            Console.WriteLine("childTask to start");
        }, TaskCreationOptions.AttachedToParent);
        childTask.Start();
        Console.WriteLine("parentTask to start");
    });
    parentTask.Start();
    //会等待父子task都执行完毕,才执行后续代码
    parentTask.Wait();
    Console.WriteLine("end");
    View Code

    Parallel

    //数组的并行执行
    List<int> nums = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    //var evenNumbers = nums.AsEnumerable().Select(item => Calculate(item));
    
    //AsOrdered 将数据以原来顺序排序返回
    var evenNumbers = nums.AsParallel().AsOrdered().Select(item =>
    {
        Console.WriteLine("针对集合元素{0}的一些工作代码……ThreadId={1}", item, Thread.CurrentThread.ManagedThreadId);
        return item * 2;
    });
    //注意这里是个延迟加载,也就是不用集合的时候 这个Calculate里面的算法 是不会去运行 可以屏蔽下面的代码看效果;
    //Console.WriteLine(evenNumbers.Count());
    foreach (int item in evenNumbers)
        Console.WriteLine(item);
    View Code
    /*
    * ****************Parallel.Invoke 主要用于任务的并行*******
    * 这个函数的功能和Task有些相似,就是并发执行一系列任务,然后等待所有完成。和Task比起来,省略了Task.WaitAll这一步,自然也缺少了Task的相关管理功能。它有两种形式:
    * Parallel.Invoke( params Action[] actions);
    * Parallel.Invoke(Action[] actions,TaskManager manager,TaskCreationOptions options);
    */
    var actions = new Action[]
    {
        () => ActionTest("test 1"),
        () => ActionTest("test 2"),
        () => ActionTest("test 3"),
        () => ActionTest("test 4")
    };
    
    Console.WriteLine("Parallel.Invoke 1 Test");
    Parallel.Invoke(actions);
    
    Console.WriteLine("结束!")
    Action[]
    //Parallel.For方法,主要用于处理针对数组元素的并行操作(数据的并行)  (无序的)
    int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    Parallel.For(0, nums.Length, i =>
    {
        Thread.Sleep(1000);
        Console.WriteLine("针对数组索引{0}对应的那个元素{1}的一些工作代码……ThreadId={2}", i, nums[i], Thread.CurrentThread.ManagedThreadId);
    });
    Parallel.For
    //Foreach方法,主要用于处理泛型集合元素的并行操作(数据的并行) 同上
    List<int> nums = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    Parallel.ForEach(nums, (item) =>
    {
        Console.WriteLine("针对集合元素{0}的一些工作代码……ThreadId={1}", item, Thread.CurrentThread.ManagedThreadId);
    });
    Parallel.ForEach
    using System;
    using System.Collections.Concurrent;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        public class Student
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public int Age { get; set; }
            public DateTime CreateTime { get; set; }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                var dic = LoadData();
                Stopwatch watch = new Stopwatch();
                watch.Start();
                var query2 = (from n in dic.Values.AsParallel()
                              where n.Age > 20 && n.Age < 25
                              select n).ToList();
                watch.Stop();
                Console.WriteLine("并行计算耗费时间:{0}", watch.ElapsedMilliseconds);
    
                Console.Read();
            }
    
            public static ConcurrentDictionary<int, Student> LoadData()
            {
                ConcurrentDictionary<int, Student> dic = new ConcurrentDictionary<int, Student>();
                ParallelOptions options = new ParallelOptions();
                //指定使用的硬件线程数为4
                options.MaxDegreeOfParallelism = 4;
                //预加载1500w条记录
                Parallel.For(0, 15000000, options, (i) =>
                {
                    var single = new Student()
                    {
                        ID = i,
                        Name = "hxc" + i,
                        Age = i % 151,
                        CreateTime = DateTime.Now.AddSeconds(i)
                    };
                    dic.TryAdd(i, single);
                });
    
                return dic;
            }
        }
    }
    并行执行线程数
    //是的,在串行代码中我们break一下就搞定了,但是并行就不是这么简单了,不过没关系,在并行循环的委托参数中提供了一个ParallelLoopState,该实例提供了Break和Stop方法来帮我们实现。
    //Break: 当然这个是通知并行计算尽快的退出循环,比如并行计算正在迭代100,那么break后程序还会迭代所有小于100的。
    //Stop:这个就不一样了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。
    
    using System;
    using System.Collections.Concurrent;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        class Program
        {
            static void Main(string[] args)
            {
                ConcurrentBag<int> bag = new ConcurrentBag<int>();
    
                Parallel.For(0, 20000000, (i, state) =>
                {
                    if (bag.Count == 1000)
                    {
                        //state.Break();
                        state.Stop();
                        return;
                    }
                    bag.Add(i);
                });
    
                Console.WriteLine("当前集合有{0}个元素。", bag.Count);
    
            }
        }
    }
    退出并行循环
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        class Program
        {
            public static void Main()
            {
    
                var cts = new CancellationTokenSource();
                var ct = cts.Token;
                Task.Factory.StartNew(() => fun(ct));
                Console.ReadKey();
                //Thread.Sleep(3000);
                cts.Cancel();
                Console.WriteLine("任务取消了!");
    
            }
    
            static void fun(CancellationToken token)
            {
                Parallel.For(0, 100000,
                            new ParallelOptions { CancellationToken = token },
                            (i) =>
                            {
                                Console.WriteLine("针对数组索引{0}的一些工作代码……ThreadId={1}", i, Thread.CurrentThread.ManagedThreadId);
                            });
            }
        }
    }
    并行取消
    using System;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Parallel.Invoke(Run1, Run2);
                }
                catch (AggregateException ex)
                {
                    foreach (var single in ex.InnerExceptions)
                    {
                        Console.WriteLine(single.Message);
                    }
                }
                Console.WriteLine("结束了!");
                //Console.Read();
            }
    
            static void Run1()
            {
                Thread.Sleep(3000);
                throw new Exception("我是任务1抛出的异常");
            }
    
            static void Run2()
            {
                Thread.Sleep(5000);
                throw new Exception("我是任务2抛出的异常");
            }
        }
    }
    异常捕获

    注意Parallel里面 不建议抛出异常 因为在极端的情况下比如进去的第一批线程先都抛异常了 此时AggregateExcepation就只能捕获到这一批的错误,然后程序就结束了

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        public class TestClass
        {
            public static List<int> NumberList = null;
            private static readonly object locker = new object();
            public void Test(int Number)
            {
                throw new Exception("1111");
                //lock (locker)
                //{
                //    if (NumberList == null)
                //    {
                //        Console.WriteLine("执行添加");
                //        NumberList = new List<int>();
                //        NumberList.Add(1);
                //        //Thread.Sleep(1000);
                //    }
                //}
                //if (Number == 5 || Number == 7) throw new Exception(string.Format("NUmber{0}Boom!", Number));
                //Console.WriteLine(Number);
            }
        }
    
        class Program
        {
            private static readonly object locker = new object();
            static void Main(string[] args)
            {
                List<string> errList = new List<string>();
                try
                {
                    Parallel.For(0, 10, (i) =>
                    {
                        try
                        {
                            TestClass a = new TestClass();
                            a.Test(i);
                        }
                        catch (Exception ex)
                        {
                            lock (locker)
                            {
                                errList.Add(ex.Message);
                                throw ex;
                            }
                        }
                    });
                }
                catch (AggregateException ex)
                {
                    foreach (var single in ex.InnerExceptions)
                    {
                        Console.WriteLine(single.Message);
                    }
                }
                int Index = 1;
                foreach (string err in errList)
                {
                    Console.WriteLine("{0}、的错误:{1}", Index++, err);
                }
            }
        }
    }
    案例

    可以像下面这样来处理一下,不在AggregateExcepation中来处理 而是在Parallel里面的try catch来记录错误,或处理错误

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace ConsoleApp1
    {
        public class TestClass
        {
            public static List<int> NumberList = null;
            private static readonly object locker = new object();
            public void Test(int Number)
            {
                throw new Exception("1111");
                //lock (locker)
                //{
                //    if (NumberList == null)
                //    {
                //        Console.WriteLine("执行添加");
                //        NumberList = new List<int>();
                //        NumberList.Add(1);
                //        //Thread.Sleep(1000);
                //    }
                //}
                //if (Number == 5 || Number == 7) throw new Exception(string.Format("NUmber{0}Boom!", Number));
                //Console.WriteLine(Number);
            }
        }
    
        class Program
        {
            private static readonly object locker = new object();
            static void Main(string[] args)
            {
                List<string> errList = new List<string>();
                Parallel.For(0, 10, (i) =>
                {
                    try
                    {
                        TestClass a = new TestClass();
                        a.Test(i);
                    }
                    catch (Exception ex)
                    {
                        lock (locker)
                        {
                            errList.Add(ex.Message);
                        }
                        //Console.WriteLine(ex.Message);
                        //注:这里不再将错误抛出.....
                        //throw ex;
                    }
                });
    
                int Index = 1;
                foreach (string err in errList)
                {
                    Console.WriteLine("{0}、的错误:{1}", Index++, err);
                }
            }
        }
    }
    View Code

    async await

    private void button2_Click(object sender, EventArgs e)
    {
        /*
            * async await是一个优雅的异步写法
            * 使用await 修饰的异步函数 返回的是 Task<T> 中的 T, 否则返回的是 Task<T>
            * async await 是成对存在的, 如果被async修饰, 但没有await 也将是一个同步函数
            */
        ConsoleUtils.PrintLine("111 balabala. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId);
        //1. 如果异步函数带有返回值, 在主函数中有使用到返回值, 则会在主函数中异步函数执行完成
        var ResultTask = AsyncMethod();
        ConsoleUtils.PrintLine(ResultTask.Result);
        ConsoleUtils.PrintLine("222 balabala. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId);
    }
    private async Task<string> AsyncMethod()
    {
        var ResultFromTimeConsumingMethod = TimeConsumingMethod();
        string Result = await ResultFromTimeConsumingMethod + " + AsyncMethod. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId;
        //2. 在await 之后的代码都是由主线程执行, 如果要返回的话,且主线程(如步骤1)主线程在等待 将会出现 [死锁]
    
        //3. 优点: 在wpf,winform等窗体中,使用这个将可以不使用 Invoke + 委托 的行,将页面数据更新交由主线程执行(这就是优雅的地方) ****
        ConsoleUtils.PrintLine(Result);
        return Result;
    }
    
    //这个函数就是一个耗时函数,可能是IO操作,也可能是cpu密集型工作。
    private Task<string> TimeConsumingMethod()
    {
        var task = Task.Run(() => {
            ConsoleUtils.PrintLine("Helo I am TimeConsumingMethod. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId, ConsoleType.Warn);
            Thread.Sleep(5000);
            ConsoleUtils.PrintLine("Helo I am TimeConsumingMethod after Sleep(5000). My Thread ID is :" + Thread.CurrentThread.ManagedThreadId, ConsoleType.Warn);
            return "Hello I am TimeConsumingMethod";
        });
    
        return task;
    }
    View Code
  • 相关阅读:
    jQuery Ajax 方法调用 Asp.Net WebService 的详细例子(原创)
    jQuery 访问WebService 返回复合类型列表
    Vista Media Center 开发之深入浅出 (一) Vista Media Center开发环境的搭建
    安装一个媒体解码器让 Windows Media Player 支持更多媒体格式
    静静期待 Windows 7 的到来
    集成 RealTek 声卡 在 Windows 7 有杂音、爆音的解决方法
    使用jQuery for Asp.Net 我的开发环境配置
    Windows 7 VHD 启动
    建立一个 C#.Net Windows Service 程序
    Windows server 2008 r2 简体中文180天评估版微软官方下载地址
  • 原文地址:https://www.cnblogs.com/Jason1019/p/12757875.html
Copyright © 2011-2022 走看看