C#异步线程总结

一. Thread

C#的所有异步多线程都是对Thread对象的封装。

  1. Thread的使用:
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(ThreadInvoke);
            thread.Start();
        }

        private void ThreadInvoke()
        {
            Console.WriteLine("Thread is running.");
        }
    }

运行结果:
在这里插入图片描述
2. 也可以使用Lambda表达式代替执行方法,运行结果与上面例子一样。

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(() =>
            {
                Console.WriteLine("Thread is running.");
            });
            thread.Start();
        }
    }
  1. 使用ThreadStart封装执行方法,运行结果与上面一样。
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ThreadStart threadStart = new ThreadStart(ThreadInvoke);
            Thread thread = new Thread(threadStart);
            thread.Start();
        }

        private void ThreadInvoke()
        {
            Console.WriteLine("Thread is running.");
        }
    }

4.IsBackground属性,可以设置该线程是否和主线程一起关闭;设置为false,当主线程关闭后,该线程还会运行,可以使用此特性进行一些关闭工作的资源释放。

二. ThreadPool

  1. 线程池使用场景更多,不用自己创建线程,从线程池中取线程使用。
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(ThreadPoolInvoke, "This is First.");
            // 线程池中只要有可用的线程,立刻调用
            ThreadPool.QueueUserWorkItem((o) =>
            {
                Console.WriteLine("线程ID:" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine(o.ToString());
            }, "This is Second.");
        }

        private void ThreadPoolInvoke(object o)
        {
            Console.WriteLine("线程ID:" + Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine(o.ToString());
        }
    }

运行结果:
C#异步线程总结_第1张图片
2. 线程池通过SetMaxThreads和GetMaxThreads设定和获取线程中最大的工作线程数量

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(ThreadPoolInvoke, "This is First.");

            ThreadPool.SetMinThreads(20, 16);
            ThreadPool.SetMaxThreads(20, 16);
            ThreadPool.GetMaxThreads(out int mW, out int mC);
            Console.WriteLine(mW + "----" + mC);
        }

        private void ThreadPoolInvoke(object o)
        {
            Console.WriteLine("线程ID:" + Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine(o.ToString());
        }
    }

运行结果:
在这里插入图片描述
3.异步等待
主线程等待异步线程的执行

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private ManualResetEvent manualResetEvent = new ManualResetEvent(false);

        private void button1_Click(object sender, EventArgs e)
        {
            
            ThreadPool.QueueUserWorkItem(ThreadPoolInvoke, null);

            // 阻止主线程继续执行,将主线程设置为等待线程,等待异步线程的执行情况。
            // 如果异步线程中,不设置manualResetEvent.Set();则该线程一直等待中,主线程陷入卡死状态。
            manualResetEvent.WaitOne();
            Console.WriteLine("World.");
        }

        private void ThreadPoolInvoke(object o)
        {
            Console.WriteLine("Hello ");

            // 允许等待线程WaitOne后的代码可以继续执行;如果没有这句代码,主线程一直因为WaitOne而等待。
            this.manualResetEvent.Set();

        }
    }

运行结果:
C#异步线程总结_第2张图片

三. Task

Task的异步线程调用

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private ManualResetEvent manualResetEvent = new ManualResetEvent(false);

        private void button1_Click(object sender, EventArgs e)
        {
            // 直接调用
            Task.Run(TaskInvoke);

            // 利用匿名委托调用
            Task.Run(delegate ()
            {
                Console.WriteLine("This is anonymous delegate invoke.");
            });

            // 利用Lambda表达式调用
            Task.Run(() =>
            {
                Console.WriteLine("This is noraml invoke.");
            });

            // 常规的调用方法
            Task task = new Task(TaskInvoke);
            task.Start();

            // 工厂模式调用
            TaskFactory taskFactory = new TaskFactory();
            taskFactory.StartNew(TaskInvoke);
            taskFactory.StartNew(() => { });
            taskFactory.StartNew(delegate () { });
        }

        private void TaskInvoke()
        {
            Console.WriteLine("This is delegate invoke.");
        }
    }

四. Task线程间的同步

1.如果不控制同步,则主线的后续代码执行顺序并不固定:

        private void button1_Click(object sender, EventArgs e)
        {
            List<Task> tasks = new List<Task>();
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));

            Console.WriteLine("OK");
        }

        private void TaskInvoke()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

两次运行结果:
C#异步线程总结_第3张图片
C#异步线程总结_第4张图片
2. 利用WhenAll方法和ContinueWith方法,所有子线程执行完毕后,才会执行ContinueWith方法中的委托

        private void button1_Click(object sender, EventArgs e)
        {
            List<Task> tasks = new List<Task>();
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));

            Task.WhenAll(tasks).ContinueWith((o) => { Console.WriteLine("OK"); });
            
        }

        private void TaskInvoke()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }
    }
  1. 先阻塞主线程,利用WaitAny,任何一个子线程执行完成,主线程都可以执行,所以每次主线程接着开始运行的地方都会不一样。
        private void button1_Click(object sender, EventArgs e)
        {
            List<Task> tasks = new List<Task>();
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));
            tasks.Add(Task.Run(() => { this.TaskInvoke(); }));

            Task.WaitAny(tasks.ToArray());
            Console.WriteLine("OK");
        }

        private void TaskInvoke()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

运行结果:

C#异步线程总结_第5张图片
C#异步线程总结_第6张图片
4. 如果需要阻塞主线程,等待所有子线程都运行完毕,再运行主线程,使用WaitAll方法。用法和WaitAny类似。其功能和await类似,但await不会阻塞主线程,因为await之后的代码会放到一个子线程里面去执行,所以主线程不会等待阻塞。

五. Parallel

  1. Parallel直接调用
        private void button1_Click(object sender, EventArgs e)
        {
            Parallel.Invoke(
                () => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); },
                () => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); },
                () => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); });
        }
  1. For并发
        private void button1_Click(object sender, EventArgs e)
        {
            ParallelOptions parallelOptions = new ParallelOptions();
            //允许的最大并发数量
            parallelOptions.MaxDegreeOfParallelism = 5;
            // 一共产生10个并发,0是起始值,10是最大计数值,i是每次的计数
            // 虽然是10个并发,但是按设置每次并发5个
            Parallel.For(0, 10, parallelOptions, (i) =>
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            });
        }

3.ForEach并发

        private void button1_Click(object sender, EventArgs e)
        {
            ParallelOptions parallelOptions = new ParallelOptions();
            //允许的最大并发数量
            parallelOptions.MaxDegreeOfParallelism = 5;

            // string[]数组作为参数,每个并发都会把string[]数组里面的一个成员传入线程执行
            Parallel.ForEach(new string[] { "go", "run" }, parallelOptions, c =>
            {
                Console.WriteLine(c);
            });
        }

运行结果:
在这里插入图片描述

你可能感兴趣的:(C#语言,c#,开发语言,java)