zoukankan      html  css  js  c++  java
  • C#读书笔记:线程,任务和同步

    前言

    学习C#两个多月了,像当初实习做PHP开发一样,也是由着一个个Feature需求,慢慢掌握了很多相关的编程技巧。本次主要记录下学习C# 多线程的相关知识。

    参考书籍:《Csharp高级编程(第7版)》

    1.使用线程的原因

     

    不过运行多个线程也要注意一些问题:他们可以同时运行,但是如果线程访问相同的数据,就很容易出问题,必须实现同步机制

     2.理解线程

     线程是程序中独立的指令流。C#编写的程序都有一个入口点(即Main()方法),程序从该方法的第一条开始执行,直到方法返回为止。这种程序结构非常适合用于一个有任务序列的程序,但是程序常常需要同时完成多个任务。

    这就要用到多个线程,比如Word的拼写检查器的工作原理是这样的:一个线程等待用户输入,另一个线程进行后台搜索,第3个线程将写入的数据保存在临时文件中,第4个线程从Internet上下载其他数据。

    理解线程很重要的一点其实是理解线程和进程的关系:

     

    3.创建线程的方式

    • 异步委托

    创建线程的一种简单地方式是定义委托,并异步调用它。委托是方法的类型安全的引用,它使用线程池来完成异步任务。

    代码实例:

    使用投票的例子,并检查委托是否完成了它的任务。等待异步委托结果的四种方式:

    (1)轮询

    Delegate类提供了BeginInvoke()方法,通过其返回类型IAsyncResult ,可以获取委托的相关信息,并检验它是否完成了任务。只要委托没有完成其任务,程序的主线程就继续执行while循环。

    (2)等待句柄

    使用与IAsyncResult 相关联的等待句柄。使用AsyncWaitHandle属性可以访问等待句柄,该属性可以返回一个WaitHandle类型的对象,它可以等待委托线程完成其任务。

    (3)异步回调

    (4)Lambda表达式 

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;
    
    namespace Wrox.ProCSharp.Threading
    {
        class Program
        {
            static int TakesAWhile(int data, int ms)
            {
                Console.WriteLine("TakesAWhile started");
                Thread.Sleep(ms);
                Console.WriteLine("TakesAWhile completed");
                return ++data;
            }
    
         //要从委托中调用这个方法,必须定义一个有相同参数和返回类型的的委托 public delegate int TakesAWhileDelegate(int data, int ms); static void Main() { // synchronous // TakesAWhile(1, 3000); TakesAWhileDelegate d1 = TakesAWhile; // (1)polling轮询 //IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null); //while (!ar.IsCompleted) //{ // // doing something else // Console.Write("."); // Thread.Sleep(50); //} //int result = d1.EndInvoke(ar); //Console.WriteLine("result: {0}", result); // (2)wait handle //IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null); //while (true) //{ // Console.Write("."); // if (ar.AsyncWaitHandle.WaitOne(50, false)) // { // Console.WriteLine("Can get the result now"); // break; // } //} //int result = d1.EndInvoke(ar); //Console.WriteLine("result: {0}", result); // (3)async callback //d1.BeginInvoke(1, 3000, TakesAWhileCompleted, d1); //for (int i = 0; i < 100; i++) //{ // Console.Write("."); // Thread.Sleep(50); //} //(4)Lambda expression:可以直接访问作用域外的变量d1,所以不需要把一个值赋予BeginInvoke()方法的最后一个参数 d1.BeginInvoke(1, 3000, ar => { int result = d1.EndInvoke(ar); Console.WriteLine("result: {0}", result); }, null); for (int i = 0; i < 100; i++) { Console.Write("."); Thread.Sleep(50); } } static void TakesAWhileCompleted(IAsyncResult ar) { if (ar == null) throw new ArgumentNullException("ar"); TakesAWhileDelegate d1 = ar.AsyncState as TakesAWhileDelegate; Trace.Assert(d1 != null, "Invalid object type"); int result = d1.EndInvoke(ar); Console.WriteLine("result: {0}", result); } } }

    运行结果:

    代码实例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace Wrox.ProCSharp.Threading
    {
        public class MyThread
        {
            private string data;
    
            public MyThread(string data)
            {
                this.data = data;
            }
    
            public void ThreadMain()
            {
                Console.WriteLine("Running in a thread, data: {0}", data);
            }
        }
    
    
    
        public struct Data
        {
            public string Message;
        }
    
    
        class Program
        {
            static void Main()
            {
                FirstThread();
    
                //var t1 = new Thread(Prio);
                //t1.Name = "First";
    
                //var t2 = new Thread(Prio);
                //t2.Name = "Second";
                //t1.Priority = ThreadPriority.Highest;
                //t2.Priority = ThreadPriority.Lowest;
    
                //t1.Start();
                //t2.Start();
    
                //var t1 = new Thread(ThreadMain);
                //t1.Name = "MyNewThread1";
                //t1.IsBackground = true;
                //t1.Start();
                //Console.WriteLine("Main thread ending now...");
    
                //var d = new Data { Message = "Info" };
                //var t2 = new Thread(ThreadMainWithParameters);
                //t2.Start(d);
    
                //var obj = new MyThread("info");
                //var t3 = new Thread(obj.ThreadMain);
                //t3.Start();
            }
    
            static void Prio()
            {
                for (int i = 0; i < 10000; i++)
                {
                    Console.WriteLine("{0}, {1}", Thread.CurrentThread.Name, i);
                }
            }
    
            static void ThreadMain()
            {
                Console.WriteLine("Thread {0} started", Thread.CurrentThread.Name);
                Thread.Sleep(3000);
                // Console.WriteLine("Running in the thread {0}, id: {1}.", Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("Thread {0} completed", Thread.CurrentThread.Name);
            }
    
            static void ThreadMainWithParameters(object o)
            {
                Data d = (Data)o;
                Console.WriteLine("Running in a thread, received {0}", d.Message);
            }
    
            static void FirstThread()
            {
                new Thread(() => Console.WriteLine("Running in a thread, id: {0}", Thread.CurrentThread.ManagedThreadId)).Start();
    
                Console.WriteLine("This is the main thread, id: {0}", Thread.CurrentThread.ManagedThreadId);
            }
        }
    }
    

    运行结果:

    代码实例:

    using System;
    using System.Threading;
    
    namespace Wrox.ProCSharp.Threading
    {
        class Program
        {
            static void Main()
            {
                int nWorkerThreads;
                int nCompletionPortThreads;
                ThreadPool.GetMaxThreads(out nWorkerThreads, out nCompletionPortThreads);
                Console.WriteLine("Max worker threads: {0}, I/O completion threads: {1}", nWorkerThreads, nCompletionPortThreads);
    
                for (int i = 0; i < 5; i++)
                {
                    ThreadPool.QueueUserWorkItem(JobForAThread);
    
                }
    
                Thread.Sleep(3000);
            }
    
    
            static void JobForAThread(object state)
            {
                for (int i = 0; i < 3; i++)
                {
                    Console.WriteLine("loop {0}, running inside pooled thread {1}", i,
                       Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(50);
                }
    
            }
        }
    }
    

    运行结果:

     代码实例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.IO;
    
    namespace TaskSamples
    {
        class Program
        {
            static void Main()
            {
                // ParallelDemo();
    
                SimpleTask();
                // ContinuationTask();
                // ParentAndChild();
                // ResultsFromTasks();
    
                Thread.Sleep(5000);
    
                //ParentAndChild();
    
                // HierarchyTasks("c:\");
    
                //Parallel.f
                //Task t1 = new Task(() => Console.WriteLine("running in a task"));
                //Task t2 = new Task(() => Console.WriteLine("running in a task"));
    
                //for (int i = 0; i < 10; i++)
                //{
                //    Task t1 = new Task(o =>
                //    {
                //        Console.WriteLine("running in a task {0}", Thread.CurrentThread.ManagedThreadId);
                //        Thread.Sleep(500);
                //        Console.WriteLine("still running {0}", Thread.CurrentThread.ManagedThreadId);
                //    }, "data", TaskCreationOptions.None);
                //    // t1.RunSynchronously();
                //    t1.Start();
    
    
    
                //}
    
    
    
                //Console.WriteLine("start sleep main");
                //Thread.Sleep(3000);
                //Console.WriteLine("main thread");
            }
    
            static void ResultsFromTasks()
            {
                var t1 = new Task<Tuple<int,int>>(TaskWithResult, Tuple.Create<int, int>(8, 3));
                t1.Start();
                Console.WriteLine(t1.Result);
                t1.Wait();
                Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2);
            }
    
            static Tuple<int, int> TaskWithResult(object division)
            {
                Tuple<int, int> div = (Tuple<int, int>)division;
                int result = div.Item1 / div.Item2;
                int reminder = div.Item1 % div.Item2;
                Console.WriteLine("task creates a result...");
    
                return Tuple.Create<int, int>(result, reminder);
            }
    
            static void SimpleTask()
            {
                // using task factory
                TaskFactory tf = new TaskFactory();
                Task t1 = tf.StartNew(TaskMethod);
    
                // using the task factory via a task
                Task t2 = Task.Factory.StartNew(TaskMethod);
    
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    
                // using Task constructor
                Task t3 = new Task(TaskMethod);
                // t3.Start();
                t3.RunSynchronously();
    
                Task t4 = new Task(TaskMethod, TaskCreationOptions.PreferFairness);
                t4.Start();
              
            }
    
            static void ContinuationTask()
            {
                Task t1 = new Task(DoOnFirst);
                Task t2 = t1.ContinueWith(DoOnSecond);
                Task t3 = t1.ContinueWith(DoOnSecond);
                Task t4 = t2.ContinueWith(DoOnSecond);          
                Task t5 = t1.ContinueWith(DoOnError, TaskContinuationOptions.OnlyOnFaulted);
                t1.Start();
    
    
                Thread.Sleep(5000);
    
            }
    
    
            static void DoOnFirst()
            {
                Console.WriteLine("doing some task {0}", Task.CurrentId);
                Thread.Sleep(3000);
            }
    
            static void DoOnSecond(Task t)
            {
                Console.WriteLine("task {0} finished", t.Id);
                Console.WriteLine("this task id {0}", Task.CurrentId);
                Console.WriteLine("do some cleanup");
                Thread.Sleep(3000);
            }
    
            static void DoOnError(Task t)
            {
                Console.WriteLine("task {0} had an error!", t.Id);
                Console.WriteLine("my id {0}", Task.CurrentId);
                Console.WriteLine("do some cleanup");
            }
    
            static void ParentAndChild()
            {
                Task parent = new Task(ParentTask);
                parent.Start();
                Thread.Sleep(2000);
                Console.WriteLine(parent.Status);
                Thread.Sleep(4000);
                Console.WriteLine(parent.Status);
    
            }
            static void ParentTask()
            {
                Console.WriteLine("task id {0}", Task.CurrentId);
                Task child = new Task(ChildTask); // , TaskCreationOptions.DetachedFromParent);
                child.Start();
                Thread.Sleep(1000);
                Console.WriteLine("parent started child");
               // Thread.Sleep(3000);
            }
            static void ChildTask()
            {
                // Console.WriteLine("task id {0}, parent: {1}", Task.Current.Id, Task.Current.Parent.Id);
                Console.WriteLine("child");
                Thread.Sleep(5000);
                Console.WriteLine("child finished");
            }
    
            static void TaskMethod()
            {
                Console.WriteLine("running in a task");
                Console.WriteLine("Task id: {0} {1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            }
    
            static void ParallelDemo()
            {
                // Parallel.For(0, 5, i => Console.WriteLine(i));
                Parallel.For<string>(0, 20, () => "abcd",
                    (x, ls, str) =>
                    {
                        Console.WriteLine(x);
                        return "defg";
                    },
                        (str) =>
                        {
                            Console.WriteLine("action {0}", str);
                        });
    
                ParallelOptions po = new ParallelOptions();
    
    
    
                   
            }
    
    
    
            //static void ParentAndChild()
            //{
            //    TaskFactory factory = new TaskFactory();
            //    var t1 = factory.StartNew(() =>
            //        {
            //            Console.WriteLine("parent task {0}", Task.CurrentId);
    
            //            factory.StartNew(() =>
            //                {
            //                    Console.WriteLine("child task {0}", Task.CurrentId);
            //                    Thread.Sleep(2000);
            //                    Console.WriteLine("finished child");
            //                }, TaskCreationOptions.AttachedToParent);
    
            //            Console.WriteLine("finished parent");
            //        });
    
            //    t1.Wait();
    
            //}
    
    
        }
    }
    

    运行结果:

    代码实例:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Wrox.ProCSharp.Threading
    {
        class Program
        {
            static void Main()
            {
                //ParallelFor();
                //ParallelForeach();
                ParallelInvoke();
            }
    
            static void ParallelInvoke()
            {
                //并行运行多个任务:Parallel.Invoke()方法允许传递一个Action委托数组,其中指定应运行的方法
                Parallel.Invoke(Foo, Bar);
            }
    
            static void Foo()
            {
                Console.WriteLine("foo");
            }
    
            static void Bar()
            {
                Console.WriteLine("bar");
            }
    
            static void ParallelForeach()
            {
                string[] data = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"};
    
                //异步方式遍历
                ParallelLoopResult result =
                    Parallel.ForEach<string>(data, s =>
                        {
                            Console.WriteLine(s);
                        });
    
    
                Parallel.ForEach<string>(data,
                    (s, pls, l) =>
                    {
                        Console.WriteLine("{0} {1}", s, l);
    
                    });
    
            }
    
            static void ParallelFor()
            {
                //ParallelLoopResult result =
                //    Parallel.For(0, 10, i =>
                //        {
                //            Console.WriteLine("{0}, task: {1}, thread: {2}", i,
                //               Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                //            Thread.Sleep(10);
    
                //        });
                //Console.WriteLine(result.IsCompleted);
    
                //ParallelLoopResult result =
                //    Parallel.For(10, 40, (int i, ParallelLoopState pls) =>
                //        {
                //            Console.WriteLine("i: {0} task {1}", i, Task.CurrentId);
                //            Thread.Sleep(10);
                //            if (i > 15)
                //                pls.Break();
                //        });
                //Console.WriteLine(result.IsCompleted);
                //Console.WriteLine("lowest break iteration: {0}", result.LowestBreakIteration);
    
    
                Parallel.For<string>(0, 20,
                    () =>
                    {
                        // invoked once for each thread
                        Console.WriteLine("init thread {0}, task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId);
                        return String.Format("t{0}", Thread.CurrentThread.ManagedThreadId);
                    },
                    (i, pls, str1) =>
                    {
                        // invoked for each member
                        Console.WriteLine("body i {0} str1 {1} thread {2} task {3}", i, str1,
                            Thread.CurrentThread.ManagedThreadId,
                            Task.CurrentId);
                        Thread.Sleep(10);
                        return String.Format("i {0}", i);
    
                    },
                    (str1) =>
                    {
                        // final action on each thread
                        Console.WriteLine("finally {0}", str1);
                    });
    
    
    
            }
        }
    }
    

    运行结果:

    代码实例:

      

      

      

    ps:在运行书中附带的sample时,报错:

    经查证,发现这是由于StartupUri中的内容与窗口名称不一致所导致。

    这部分的知识可以参考一篇译文:WPF教程(十)使用App.xaml

  • 相关阅读:
    Locust性能测试-环境准备与基本使用 转自:悠悠
    Locust性能测试_先登录场景案例
    python_协程
    python_进程池以及线程池
    python_并发与通信
    python_进程与线程的补充
    python_并行与并发、多线程
    Hash算法:双重散列
    AVL树的插入和删除
    查找最小生成树:普里姆算法算法(Prim)算法
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/7207556.html
Copyright © 2011-2022 走看看