zoukankan      html  css  js  c++  java
  • (29)C#多线程

    使用线程的原因

    1.不希望用户界面停止响应。

    2.所有需要等待的操作,如文件、数据库或网络访问需要一定的时间。

    一个进程的多个线程可以同时运行不同cpu或多核cpu的不同内核上

    注意多线程访问相同的数据必须实现同步机制

    编写能够利用并行性的代码需要区分两种场景:任务并行性和数据并行性

    任务并行性:使用CPU的代码被并行化,利用cpu的多个核心快速的完成包含多个任务的活动。

    数据并行性:使用了数据集合,在集合上执行的工作被划分为多个任务。

    任务并行性和数据并行性可以混合起来。

    Parallel类(自 4.0 起可用)

    Parallel类定义了并行的for和foreach的静态方法,使用多线程来完成作业。

    Parallel.For()和Parallel.ForEach()方法再每次迭代中调用相同的代码。而Parallel.Invoke()方法允许同时调用不同的方法。

    Parallel.Invoke()用于任务并行性,Parallel.Invoke()用于数据并行性。

    Parallel.For()

    using System.Threading;
    using System.Threading.Tasks;
        class Program
        {     
            static void Main(string[] args)
            {
     
                //参数1 int ,参数2 int,参数3 action<int>
                Parallel.For(3, 10, (i)=> {
                    Console.WriteLine("id:" + i + "   thread:" + Thread.CurrentThread.ManagedThreadId);
                });
                Console.WriteLine("end");
                Console.ReadLine();
            }
        }

    参数3的action中可以添加一个控制状态的类型

    Action<Int32,ParallelLoopState>)

    使用 Break()和Stop()尽早的结束循环,在结束前启动的线程仍可以继续执行。

    Break() 尽早结束当前以外的线程

    Stop() 尽早结束

        class Program
        {     
            static void Main(string[] args)
            {
                
                Parallel.For(3, 100000, (i, state) => {
                    if (i > 6)
                    {
                        state.Stop();
                        Console.WriteLine("abc");
                    }
                    Console.WriteLine("id:" + i + "   thread:" + Thread.CurrentThread.ManagedThreadId);
                });
                Console.WriteLine("end");
                Console.ReadLine();
            }
        }

    Parallel.ForEach()

    用来遍历一个能被迭代的集合,相当于一个多线程的foreach版

        class Program
        {     
            static void Main(string[] args)
            {
                int[] count = { 2, 3, 6, 4, 7, 25, 42, 612, 12 };
                Parallel.ForEach(count, (i, state) => {
       
                    Console.WriteLine("id:" + i + "   thread:" + Thread.CurrentThread.ManagedThreadId);
                });
                Console.WriteLine("end");
                Console.ReadLine();
            }
        }

    Parallel类返回类型

    Parallel.for 和 Parallel.foreach 返回 ParallelLoopResult 类型,用来判断是否执行完成
        class Program
        {
            static void Main(string[] args)
            {
                ParallelLoopResult res = Parallel.For(3, 10, (i, state) => {
                    Console.WriteLine("id:" + i + "   thread:" + Thread.CurrentThread.ManagedThreadId);
                });
                Console.WriteLine(res.IsCompleted);
                Console.ReadLine();
            }
        }

     

    Parallel.Invoke()

    public static void Invoke (params Action[] actions) ,可以调用多个不同的方法

        class Program
        {
            static void Main(string[] args)
            {
                Parallel.Invoke(a,b);
                Console.WriteLine("end");
                Console.ReadLine();
            }
    
            static public void a()
            {
                Console.WriteLine("a");
            }
            static public void b()
            {
                Console.WriteLine("b");
            }
        }

     任务

     1.工厂类的方式启动一个线程

            static void Main(string[] args)
            {
                var tf = new TaskFactory();
                Task task = tf.StartNew(abc);
                Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
                Console.ReadLine();
            }
    
            static public void abc()
            {
                Console.WriteLine("abc:"+ Thread.CurrentThread.ManagedThreadId);
            }

     

    2.Task的静态Factory属性启动线程

            static void Main(string[] args)
            {
        
                Task task = Task.Factory.StartNew(abc);
                Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
                Console.ReadLine();
            }

    3.使用Task的构造函数

     实例化后不会立即启动线程,当对象调用Start()方法时才开始启动

            static void Main(string[] args)
            {
        
                Task task =new Task(abc);
                task.Start();
                Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
                Console.ReadLine();
            }

     4.使用Task的静态Run方法

            static void Main(string[] args)
            {
                Task task =Task.Run(abc);
                Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
                Console.ReadLine();
            }

    5.使用Task同步运行

            static void Main(string[] args)
            {
                Task task =new Task(abc);
                task.RunSynchronously();
                Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
                Console.ReadLine();
            }

    6.使用单独的线程,而不是线程池

            static void Main(string[] args)
            {
                Task task =new Task(abc,TaskCreationOptions.LongRunning);
                task.Start();
                Console.WriteLine("main:"+Thread.CurrentThread.ManagedThreadId);
                Console.ReadLine();
            }

    7.带返回值的任务

      Func<>   返回Task<TResult>

            static void Main(string[] args)
            {
                Task<int> task =Task<int>.Run(()=>{
                    Console.WriteLine("111");
                    return 5;
                });
                Console.WriteLine(task.Result);
                Console.WriteLine("abc");
                Console.ReadLine();
            }

    task.Result会等到Task执行完才会被调用相当于调用的wait,所以abc会在结果打印之后再打印

    8.连续的任务

     ContinueWith

            static void Main(string[] args)
            {
                Task task1 = new Task(a);
                Task task2 = task1.ContinueWith(b);
                Task task3 = task2.ContinueWith(c);
                task1.Start();
                Console.WriteLine("end");
                Console.ReadLine();
            }
    
            static public void a()
            {
                Console.WriteLine("a:" + Thread.CurrentThread.ManagedThreadId);
            }
    
            static public void b(Task t)
            {
                Console.WriteLine("b:" + Thread.CurrentThread.ManagedThreadId);
            }
    
            static public void c(Task t)
            {
                Console.WriteLine("c:" + Thread.CurrentThread.ManagedThreadId);
            }

     

    9.连续任务控制

    使用TaskContinuationOptions的枚举成员,上一步出现某种问题时,来确定是否执行现在的方法

            static void Main(string[] args)
            {
                Task task1 = new Task(a);
                Task task2 = task1.ContinueWith(b,TaskContinuationOptions.DenyChildAttach);
                task1.Start();
                Console.WriteLine("end");
                Console.ReadLine();
            }

     10.任务的层次

    11.

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

    Thread类

        class Program
        {
            static void Main(string[] args)
            {
                Thread t1 = new Thread(M);
                t1.Start();
                //Thread.Sleep(1000);
                Console.WriteLine("BBB");
                Console.ReadKey();
            }
    
            static void M()
            {
               
                Console.WriteLine("AAA");
            }
        }

    先输出AAA,还是BBB取决于操作系统调度

    委托方式,输出结果和上列子相同

        class Program
        {
            static void Main(string[] args)
            {
                Thread t1 = new Thread(() => Console.WriteLine("AAA"));
                t1.Start();
                Thread.Sleep(1000);
                Console.WriteLine("BBB");
                Console.ReadKey();
            }
        }

    给线程传递数据

     方法一,启动线程时传递参数

        class Program
        {
            static void Main(string[] args)
            {
                C c = new C { Message="hello" };
                Thread t = new Thread(ThreadM);
                t.Start(c);//线程启动时传参
                Console.ReadKey();
            }
    
            static void ThreadM(object O)
            {
                C c = (C)O;
                Console.WriteLine("AAA:{0}",c.Message);
            }
        }
        public class C
        {
            public string Message;
        }

    方法二、自定义类

        class Program
        {
            static void Main(string[] args)
            {
                C c = new C ("hello");
                Thread t = new Thread(c.ThreadMain);
                t.Start();
                Console.ReadKey();
            }
        }
        public class C
        {
            public string Message;
            //构造函数
            public C(string Message)
            {
                this.Message = Message;
            }
    
            public void ThreadMain()
            {
                Console.WriteLine("AAA:{0}",Message);
            }
        }

    后台线程

    前台线程可以有多个,后台线程也可以有多个。只要有一个前台线程在运行,程序的Main方法就不算结束。

    Thread类创建的是前台线程。线城池中的线程时后台线程。

            static void Main(string[] args)
            {
                //IsBackground默认为false,表示为前台线程
                Thread t = new Thread(ThreadMain) { Name="线程",IsBackground=false};
                t.Start();
                Console.WriteLine("AAA");
                Console.ReadKey();
            }
    
    
            public static void ThreadMain()
            {
                Console.WriteLine("{0}启动",Thread.CurrentThread.Name);
                Thread.Sleep(6000);
            }
        }

    如果IsBackground=false,按任意键后,会等执行完sleep方法才会结束。

    如果IsBackground=true,按任意键后会立即结束。

    这说明,如果有一个前台线程没执行完,Main方法就算都执行完,也要等到前台程序执行完才算是结束。

    线程优先级

     线程的priority属性可以控制线程的优先级

    它是一个枚举类型

    Highest > AboveNormal > Normal > BelowNormal > Lowest

        class Program
        {
            static void Main(string[] args)
            {
                Thread t1 = new Thread(ThreadMain) { Name = "A", Priority = ThreadPriority.Lowest };
                Thread t2 = new Thread(ThreadMain) { Name = "B", Priority = ThreadPriority.Highest };
                Thread t3 = new Thread(ThreadMain) { Name = "C", Priority = ThreadPriority.Normal };
                t1.Start();
                t2.Start();
                t3.Start();
                Console.ReadKey();
            }
            public static void ThreadMain()
            {
                Thread.Sleep(1000);
                for (int i = 0; i < 5000; i++)
                {
                    Console.Write("{0}", Thread.CurrentThread.Name);
                }
            }
        }

    线程优先级高的占用的CPU会更多一些

    线程问题

    争用条件

    如果两个或多个线程访问相同的对象,并且对共享状态的访问没有同步,就会出现争用条件。

    解决办法:加一个lock锁,只能锁引用类型

        class Program
        {
          static  object o = new object();
            static void Main(string[] args)
            {
    
            }
            public static void a()
            {
                lock (Program.o)
                {
                    .....
                }
            }
        }

    死锁

    锁定过多可能会引发死锁问题

    同步

  • 相关阅读:
    (转载)Rime输入法—鼠须管(Squirrel)词库添加及配置
    (转载)Windows下小狼毫输入法(Rime)的安装与配置(含导入搜狗词库)
    (转载)WinCC 卸载后 Simatic Shell 的删除
    (转载)西门子PLC学习笔记十五-(数据块及数据访问方式)
    (转载)一张表搞清楚西门子S7系列标准DB块与优化DB块
    (转载)Navicat Premium 12.1.16.0安装与激活
    (转载)MySQl数据库-批量添加数据的两种方法
    (转载)用C#实现MySQL建库及建表
    设置MYSQL数据库编码为UTF-8
    [设计模式]工厂方法模式(Factory Method)
  • 原文地址:https://www.cnblogs.com/buchizaodian/p/6538966.html
Copyright © 2011-2022 走看看