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)
                {
                    .....
                }
            }
        }

    死锁

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

    同步

  • 相关阅读:
    LeetCode120 Triangle
    LeetCode119 Pascal's Triangle II
    LeetCode118 Pascal's Triangle
    LeetCode115 Distinct Subsequences
    LeetCode114 Flatten Binary Tree to Linked List
    LeetCode113 Path Sum II
    LeetCode112 Path Sum
    LeetCode111 Minimum Depth of Binary Tree
    Windows下搭建PHP开发环境-WEB服务器
    如何发布可用于azure的镜像文件
  • 原文地址:https://www.cnblogs.com/buchizaodian/p/6538966.html
Copyright © 2011-2022 走看看