zoukankan      html  css  js  c++  java
  • 线程理论

    什么是进程?

    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。

    而一个进程又是由多个线程所组成的。

    什么是线程?

    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。

    什么是多线程?

    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

    多线程的好处: 

    可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。

    多线程的不利方面:

    线程也是程序,所以线程需要占用内存,线程越多占用内存也越多; 

    多线程需要协调和管理,所以需要CPU时间跟踪线程; 

    线程之间对共享资源的访问会相互影响,必须解决竞用共享资源的问题;

    线程太多会导致控制太复杂,最终可能造成很多Bug

    Thread

           static void Main(string[] args)

            {

                #region Thread无参数举例

                Thread th = new Thread(ThreadChild);

                th.Start();

                Console.WriteLine("Main Thread Start!");

                #endregion

            }

            static void ThreadChild()

            {

                Console.WriteLine("Child Thread Start!");

            }

    //带参数

      static void Main(string[] args)

            {     

                #region 使用parameterizedThreadStart委托执行带参数的委托

                Thread th2 = new Thread(Thread_param);

                th2.Start(20);

                #endregion         

            }

            static void Thread_param(object msg)

            {

                int message = (int)msg;

                Console.WriteLine("Result:{0}",message);

            }

    上面创建的线程是类型不安全的,那用什么样的方式执行带传入参数的线程的方法是类型安全的呢,答案就是创建一个自定义类,在类中定义一个作为传入参数的字段,将线程的主方法定义为一个类的实例方法。然而使用这种方法就可以使用泛型来解决使用ParameterizedThreadStart的类型不安全

    看招!!!!

    class Program

        {

            static void Main(string[] args)

            {

                #region 使用自定义类实现带参数的线程

                MyThread<string> mythread = new MyThread<string>("Thread_child");

                Thread th3 = new Thread(mythread.ThreadChild);

                th3.Start();

                #endregion

            }

        }

        class MyThread<T>

        {

            private T data;

            public MyThread(T data)

            {

                this.data = data;

            }

            public void ThreadChild()

            {

                Console.WriteLine("Child Thread Start! Result:{0}",data);

            }

    }

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

    string name = string.Format("123");

    ThreadStart method = () => this.TestThread(name);

    Thread thread = new Thread(method);//1 默认前台线程:程序退出后,计算任务会继续

    thread.IsBackground = true;//2 后台线程:程序退出,计算立即结束

    thread.Start();

    threadList.Add(thread);

    ParameterizedThreadStart method = o => this.TestThread(o.ToString());

    //Thread thread = new Thread(method);

    //thread.Start(name);

    static void PrintNumbers()

    {

    Console.WriteLine("Starting...");

    for (int i = 0; i < 10; i++)

    {

    Console.WriteLine(i);

    }

    }

    //注意:要使用ParameterizedThreadStart,定义的参数必须为object

    static void PrintNumbers(object count)

    {

    Console.WriteLine("Starting...");

    for (int i = 0; i < Convert.ToInt32(count); i++)

    {

    Console.WriteLine(i);

    }

    }

    Thread t1 = new Thread(new ThreadStart(PrintNumbers));//无参数的委托 t1.Start(); Thread t2 = new Thread(new ParameterizedThreadStart(PrintNumbers));//有参数的委托 t2.Start(10);

    多个线程等待

    List<Thread> threadList = new List<Thread>();

    for (int i = 0; i < 5; i++)

    {

    string name = string.Format("btnThread_Click_{0}", i);

    ThreadStart method = () => this.TestThread(name);

    Thread thread = new Thread(method);//1 默认前台线程:程序退出后,计算任务会继续

    thread.IsBackground = true;//2 后台线程:程序退出,计算立即结束

    thread.Start();

    threadList.Add(thread);

    }

    foreach (Thread thread in threadList)

    {

    thread.Join();将线程插入主线程,若把这句放到上面相当于单线程啦。

    }

    /// <summary>

    /// 使用Thread 完成多线程回调

    /// </summary>

    /// <param name="method">要多线程执行的任务</param>

    /// <param name="callback">回调执行的任务</param>

    private void ThreadBeginInvoke(ThreadStart method, Action callback)

    {

    ThreadStart methodAll = new ThreadStart(() =>

    {

    method.Invoke();

    callback.Invoke();

    });

    Thread thread = new Thread(methodAll);

    thread.Start();

    }

    ThreadPool

    线程池,用资源换时间 都是后台线程

          上面介绍了介绍了平时用到的大多数的多线程的例子,但在实际开发中使用的线程往往是大量的和更为复杂的,这时,每次都创建线程、启动线程。从性能上来讲,这样做并不理想(因为每使用一个线程就要创建一个,需要占用系统开销);从操作上来讲,每次都要启动,比较麻烦。为此引入的线程池的概念。

      好处:

      1.减少在创建和销毁线程上所花的时间以及系统资源的开销 

      2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”。

    在什么情况下使用线程池? 

        1.单个任务处理的时间比较短 

        2.需要处理的任务的数量大 

    线程池最多管理线程数量=“处理器数 * 250”。也就是说,如果您的机器为2个2核CPU,那么CLR线程池的容量默认上限便是1000

    通过线程池创建的线程默认为后台线程,优先级默认为Normal。

    //ThreadPool.SetMaxThreads(8, 8);//最小也是核数

    //ThreadPool.SetMinThreads(8, 8);

    static void Main(string[] args)

    {

    ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod1), new object()); //参数可选

    Console.ReadKey();

    }

    public static void ThreadMethod1(object val)

    {

    for (int i = 0; i <= 500000000; i++)

    {

    if (i % 1000000 == 0)

    {

    Console.Write(Thread.CurrentThread.Name);

    }

    }

    }

    string name = string.Format("btnThreadPool_Click_{0}", i);

    WaitCallback method = t => this.TestThread(t.ToString());

    ThreadPool.QueueUserWorkItem(method, name);

    线程池等待

    ManualResetEvent mre = new ManualResetEvent(false);

    new Action(() =>//false 则关闭,该线程一直走不下去

    {//这里异步打开

    Thread.Sleep(5000);

    Console.WriteLine("委托的异步调用");

    mre.Set();//打开

    }).BeginInvoke(null, null);

    mre.WaitOne();

    Console.WriteLine("12345");

    mre.Reset();//关闭

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

    ManualResetEvent mre = new ManualResetEvent(false);

    WaitCallback method = t =>

    {

    this.TestThread(t.ToString());

    mre.Set();

    };

    ThreadPool.QueueUserWorkItem(method, "TestManualResetEvent");

    Console.WriteLine("我们来干点别的。。。。");

    Console.WriteLine("我们来干点别的。。。。");

    Console.WriteLine("我们来干点别的。。。。");

    Console.WriteLine("我们来干点别的。。。。");

    mre.WaitOne();

    Task 都是后台线程 基于线程池的

    TaskFactory taskFactory = new TaskFactory();

    for (int i = 0; i < 5; i++)

    {

    string name = string.Format("btnAsync_Click_{0}", i);

    Action act = () => this.TestThread(name);

    //taskFactory.StartNew(act);

    //Task task = new Task(act);

    //task.Start();

    Task task = Task.Run(act);

    }

    线程等待

    List<Task> taskList = new List<Task>();

    Task any = taskFactory.ContinueWhenAny(taskList.ToArray(), t =>

    {

    //t.AsyncState

    Console.WriteLine("这里是ContinueWhenAny {0}", Thread.CurrentThread.ManagedThreadId);

    });

    Task all = taskFactory.ContinueWhenAll(taskList.ToArray(), tList =>

    {

    Console.WriteLine("这里是ContinueWhenAll {0}", Thread.CurrentThread.ManagedThreadId);

    });

    不卡线程

    Task.WaitAny(taskList.ToArray());//执行的线程等待某一个task的完成

    Console.WriteLine("after WaitAny{0}", Thread.CurrentThread.ManagedThreadId);

    Task.WaitAll(taskList.ToArray());//执行的线程等待全部的task的完成

    Console.WriteLine("after WaitAll{0}", Thread.CurrentThread.ManagedThreadId);

    卡线程,不一定是主线程

    Parallel 基于task

    主线程参与计算

    //Parallel.Invoke(() => this.TestThread("btnParallel_Click_0")

    // , () => this.TestThread("btnParallel_Click_1")

    // , () => this.TestThread("btnParallel_Click_2")

    // , () => this.TestThread("btnParallel_Click_3")

    // , () => this.TestThread("btnParallel_Click_4"));

    //等于使用4个task,然后主线程同步invoke一个委托 然后主线程waitall

    //Parallel.For(6, 10, t =>

    //{

    // string name = string.Format("For btnParallel_Click_{0}", t);

    // this.TestThread(name);

    //});

    //Parallel.ForEach(new int[] { 5, 6, 7, 10, 8473847 }, t =>

    //{

    // string name = string.Format("ForEach btnParallel_Click_{0}", t);

    // this.TestThread(name);

    //});

    ParallelOptions parallelOptions = new ParallelOptions()

    {

    MaxDegreeOfParallelism = 5//控制线程个数

    };

    Parallel.For(6, 15, parallelOptions, (t, state) =>

    {

    string name = string.Format("btnParallel_Click_{0}", t);

    this.TestThread(name);

    //state.Break();//退出单次循环

    //state.Stop();//退出全部的循环

    //return;

    });

  • 相关阅读:
    微信小程序里自定义组件,canvas组件没有效果
    微信小程序填坑之路(三):布局适配方案(rpx、px、vw、vh)
    小程序checkbox调整大小
    css让文字竖着排列 writing-mode 属性
    微信小程序 位置定位position详解,相对定位relative,绝对定位absolute相关问题
    小程序国际化实现方式
    mybatis plus 学习
    cesium js学习一加载三维模型【转】
    cesiumjs学习笔记之三——cesium-navigation插件 【转】
    局域网Cesium离线影像及瓦片影像地图加载【转】
  • 原文地址:https://www.cnblogs.com/anyihen/p/12773258.html
Copyright © 2011-2022 走看看