c#中的线程,任务,并发编程

本文深入探讨了线程、任务及并发编程的基本概念和技术实践,包括异步委托调用、线程参数传递、线程调度、线程池应用、任务连续执行、并行编程等核心主题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程,任务,并发编程

异步委托

异步调用有返回值的委托和没返回值的委托。

 

异步调用无返回值的委托

  

  PrintSomething printFruit = (d) =>

    {

        Thread.Sleep(3000);

        Console.WriteLine("\n\ryou input this fruit:"+d);

    };

 

    IAsyncResult result = printFruit.BeginInvoke("orange", null, null);

    Console.Write("Longing");

    while (!result.IsCompleted)

    {

        Console.Write(".");

        Thread.Sleep(100);

                

    }


执行结果

 Longing...............................

you input this fruit:orange

 

异步调用有返回值的委托

    //异步调用有返回值的委托  

    getSum factorial = (i) =>

    {

        Thread.Sleep(5000);

        int tmp = 1;

        for (int index = 1; index <= i; index++)

        {

            tmp *= index;

        }

        return tmp;

    };

           

    //这个调用添加了回调函数

    IAsyncResult result = factorial.BeginInvoke(10, (d) => {

        getSum tmp = d.AsyncState as getSum;

        Trace.Assert(tmp != null, "回调参数转换失败");

 

   Console.WriteLine(

string.Format("\nfinished.this result is:{0}"

,tmp.EndInvoke(d)));

      }, factorial); //factorial.beginInvoke

 

    Console.Write("Computing");

    while (!result.IsCompleted)

    {

        Console.Write(".");

        //Thread.Sleep(100);

        result.AsyncWaitHandle.WaitOne(100);

 

    }

    //如果不添加回调函数就用这个

// Console.WriteLine(

string.Format("\nresult is {0}"

, factorial.EndInvoke(result)));


 

执行结果

 Computing...................................................

finished.this result is:3628800

 

 

 

给线程传递参数

   很多时候我们生成的线程需要根据参数来工作,这时候就要给他们传递参数了。给线程传递参数必须保证在线程的声明周期内参数的可访问性。有两种比较常用的方法给线程传递参数,他们分别为:

方法一:

 

   Thread myThread = new Thread((data1) => {

        Hashtable table = data1 as Hashtable;

        foreach (string k in table.Keys)

        {

            Console.WriteLine(table[k]);

        }

    });

 

    Hashtable myTable = new Hashtable();

    myTable["1"] = "data1";

    myTable["2"] = "data2";

    myTable["3"] = "data3";

    myTable["4"] = "data4";

    myTable["5"] = "data5";

 

 

    myThread.Start(myTable);


 

执行结果:

 data1

data2

data3

data4

data5

 

 方法二:

   

 MyClass myClass = new MyClass();

    myClass.Data = "Bomb";

    Thread myThread = new Thread(myClass.PrintSomething);

    myThread.Start();

 

        public class MyClass {

            public string Data { get; set; }

 

            public void PrintSomething() {

                Console.WriteLine("this data is:" + Data);

            }


 

执行结果:

 this data is:Bomb

 

 

线程调度

一些线程的常用方法:挂起,中断,激活。

Thread bgThread=new Thread(

()=>{

Thread.Sleep(3000);

 Console.WriteLine("\nFinished!");

});

           

    bgThread.IsBackground = false;//设置线程是否为后台线程

 

    bgThread.Start();//开始

 

Console.WriteLine(

string.Format("The thread state is:{0}"

, bgThread.ThreadState));

 

    bgThread.Suspend();//挂起

 

Console.WriteLine(

string.Format("The thread state is:{0}"

, bgThread.ThreadState));

 

    Console.WriteLine("Do you want to continue the thead? Y/N"); 

    ConsoleKeyInfo input = Console.ReadKey();

    if (input.KeyChar.toString().toUpper() == “Y”)

    {

        bgThread.Resume();  //继续

    }

 

    Console.WriteLine("Do you want to stop the thead? Y/N");

 

    input = Console.ReadKey();

    if (input.KeyChar.toString().toUpper() == “Y”)

    {

        bgThread.Abort();  //取消

               

    }

 

    bgThread.Join();//阻塞当前线程,直到线程bgThread执行完毕


 

通过线程运行的优先级别来进行调度

Thread thread1 = new Thread(

() => { 

Thread.Sleep(5000); 

Console.WriteLine("thread1");

 });

 

Thread thread2 = new Thread(

() => { Thread.Sleep(5000); 

Console.WriteLine("thread2"); 

});

 

Thread thread3 = new Thread(

() => {

 Thread.Sleep(5000);

 Console.WriteLine("thread3");

 });

 

Thread thread4 = new Thread(

() => { 

Thread.Sleep(5000); 

Console.WriteLine("thread4"); 

});

 

Thread thread5 = new Thread(

() => { 

Thread.Sleep(5000);

 Console.WriteLine("thread5");

 });

 

    thread1.Priority = ThreadPriority.Lowest;

    thread2.Priority = ThreadPriority.BelowNormal;

    thread3.Priority = ThreadPriority.Normal;

    thread4.Priority = ThreadPriority.AboveNormal;

    thread5.Priority = ThreadPriority.Highest;

 

    thread1.Start();

    thread2.Start();

    thread3.Start();

    thread4.Start();

    thread5.Start();


 

执行结果:

 thread2

thread3

thread4

thread5

thread1

 

 

 

线程池

都叫“池”了,当然是为了提高系统的性能,去除频繁实例化线程的额外开销。

    //线程池 

    int workerThreads, completionPortThreads;

ThreadPool.GetMaxThreads(

out workerThreads

, out completionPortThreads);

 

Console.WriteLine(

string.Format("WorkerThread Num:{0}

,CompletionPortThreads Num:{1}"

, workerThreads

, completionPortThreads));

 

    //var testMethod = () => Console.WriteLine("ok");

 

    for (int i = 1; i < 20; i++)

    {

        ThreadPool.QueueUserWorkItem(

(o) => {

 Console.WriteLine("Current Thread Id:{0}"

, Thread.CurrentThread.ManagedThreadId);

 Thread.Sleep(100); });//writeline

    }//for

 


 

 

执行结果:

 WorkerThread Num:1023,CompletionPortThreads Num:1000

Current Thread Id:7

Current Thread Id:12

Current Thread Id:11

Current Thread Id:13

Current Thread Id:7

Current Thread Id:12

Current Thread Id:11

Current Thread Id:13

Current Thread Id:7

Current Thread Id:11

Current Thread Id:12

Current Thread Id:13

Current Thread Id:7

Current Thread Id:12

Current Thread Id:11

Current Thread Id:7

Current Thread Id:13

Current Thread Id:12

Current Thread Id:11

 

 

 

任务

   感觉和线程差不多,只是添加了更多的可控性。比如:可以按照一定的逻辑连续运行;根据上一任务的运行情况来执行相应的任务。

   

TaskFactory taskFactory = new TaskFactory();

Task myTask1 = taskFactory.StartNew(

() => Console.WriteLine("Hello Task1")

);

    

Task myTask2 = Task.Factory.StartNew(

() => Console.WriteLine("Hello Task2")

);

 

Task myTask3 = new Task(

() => Console.WriteLine("Hello Task3")

);

    myTask3.Start();

 


 

执行结果:

 Hello Task1

Hello Task2

Hello Task3

 

 

 

连续执行任务(包含出错处理): 

  //连续执行任务

Task task1 = new Task(

() => { 

Thread.Sleep(1000);

 Console.WriteLine(DateTime.Now.ToString("ss"));

 });

 

Task task2 = task1.ContinueWith(

(t) => { 

Thread.Sleep(1000);

 Console.WriteLine(DateTime.Now.ToString("ss"));

 });

 

Task task3 = task2.ContinueWith(

(t) => { 

Thread.Sleep(1000);

 Console.WriteLine(DateTime.Now.ToString("ss")); 

});

 

Task task4 = task3.ContinueWith(

(t) => { 

Thread.Sleep(1000);

 Console.WriteLine(DateTime.Now.ToString("ss"));

 throw new Exception("error");

 });

 

//当任务出错了执行

Task task5 = task4.ContinueWith(

(t) => Console.WriteLine("之前的任务出了错")

, TaskContinuationOptions.OnlyOnFaulted);

 

task1.Start();

 


 

 

执行结果:

 45

46

47

48

之前的任务出了错

 

 

 

有返回值的任务:

 var myTask = new Task<int>(() => 1);

 

    myTask.Start();

 

    Console.WriteLine(string.Format("The result is:{0}", myTask.Result));

 

    myTask.Wait(-1);

 


 

执行结果:

 The result is:1

 

 

 

并行编程

   .Net4中添加了2个并行编程的方法:for和foreach。通过使用这两个方法体可以简单的使用并行技术来编程程序。

    //并行编程

Parallel.For(

0

,10

, (index) => Console.WriteLine("current task is:" 

+ index.ToString()));

 


 

执行结果:

 current task is:0

current task is:2

current task is:1

current task is:3

current task is:4

current task is:6

current task is:8

current task is:5

current task is:9

current task is:7

 

 

 

 

并行编程(For)

   

 Parallel.For(1, 20,

                    (index, state) =>

                    {

                        if (index % 2 == 0)

                        {

                            //state.Break();//终止并发操作

Console.WriteLine(

string.Format("{0}:Current task id:{1}"

, index

, Thread.CurrentThread.ManagedThreadId));

                        }//if

 

                    });//paraller.for

 


 

执行结果:

 2:Current task id:10

4:Current task id:10

10:Current task id:11

6:Current task id:10

12:Current task id:11

14:Current task id:12

8:Current task id:10

18:Current task id:12

16:Current task id:11

 

 

//第一个委托参数:执行任务的线程开始运行时触发

//第二个委托参数:执行迭代任务的委托

//第三个委托参数:执行任务的线程结束运行时触发

Parallel.For<string>(1

, 

20

, () =>

{

Console.WriteLine(string.Format("Thread:{0} is working!",

 Thread.CurrentThread.ManagedThreadId));

         return Thread.CurrentThread.ManagedThreadId.ToString();

       }//第一个委托参数

,

      (index, state, head) =>

      {

          Thread.Sleep(100);

          Console.WriteLine(

string.Format("Current Thread is {0}

,Current Loop index is {1}"

, head

, index));

          return head;

 

       }//第二个委托参数

,

      (data) => Console.WriteLine(string.Format("thread:{0} is finished!", data))

      );//For

 


 

执行结果:

 Thread:8 is working!

Thread:9 is working!

Thread:10 is working!

Thread:11 is working!

Current Thread is 8,Current Loop index is 1

Thread:12 is working!

Current Thread is 9,Current Loop index is 5

Current Thread is 10,Current Loop index is 9

Current Thread is 11,Current Loop index is 13

Current Thread is 8,Current Loop index is 2

Current Thread is 12,Current Loop index is 17

Current Thread is 9,Current Loop index is 6

Current Thread is 10,Current Loop index is 10

Current Thread is 11,Current Loop index is 14

Current Thread is 8,Current Loop index is 3

Current Thread is 12,Current Loop index is 18

Current Thread is 9,Current Loop index is 7

thread:9 is finished!

Current Thread is 10,Current Loop index is 11

Thread:9 is working!

thread:10 is finished!

Current Thread is 8,Current Loop index is 4

Current Thread is 11,Current Loop index is 15

Current Thread is 12,Current Loop index is 19

Thread:10 is working!

thread:11 is finished!

thread:12 is finished!

Current Thread is 9,Current Loop index is 8

thread:9 is finished!

Current Thread is 8,Current Loop index is 16

Current Thread is 10,Current Loop index is 12

thread:8 is finished!

thread:10 is finished!

 

 

 

ForEach方法:

//Parallel.ForEach方法

string[] fruit = new string[] { "Orange"

, "Banana"

, "Apple"

, "Pear"

, "Grape"

, "Watermelon"

, "Pineapple"

, "Coconut"

, "Kiwifruit"

, "Lemon" };

 

    Parallel.ForEach<string>(fruit, (data) => { Thread.Sleep(1000); Console.WriteLine(data); });

 

 

    Parallel.ForEach<string>(fruit, (data, state, index) =>

    {

        Console.WriteLine(string.Format("{0}:{1}", index, data));

    });

 


 

执行结果:

 Orange

Apple

Grape

Kiwifruit

Pineapple

Banana

Watermelon

Pear

Lemon

Coconut

0:Orange

2:Apple

4:Grape

3:Pear

1:Banana

6:Pineapple

5:Watermelon

8:Kiwifruit

7:Coconut

9:Lemon

 

 

并发调用委托

    //并发调用多个委托

    Parallel.Invoke( () => Console.WriteLine("1")

                    , () => Console.WriteLine("2")

                    , () => Console.WriteLine("3")

                    , () => Console.WriteLine("4")

                    , () => Console.WriteLine("5")

                    , () => Console.WriteLine("6")

                    , () => Console.WriteLine("7")

                    , () => Console.WriteLine("8")

                    , () => Console.WriteLine("9")

                    , () => Console.WriteLine("10")

                    );

 


 

 

并发编程,根据逻辑取消任务的执行

//并发编程中的任务取消操作

//简介:该例子会在下面这个Parallel.For方法体开始执行100毫秒后终止它。

            

    var cancel = new CancellationTokenSource();

cancel.Token.Register(

()=>string.Format("Thread:{0} was canceled!"

,Thread.CurrentThread.ManagedThreadId));

 

    new Task(() =>

    {

        Thread.Sleep(100);

        cancel.Cancel();

        Console.WriteLine("Operation was canceled!");

    }).Start();

 

 

    try

    {

        ParallelLoopResult result = Parallel.For(0

                                    , 100

                                    , new ParallelOptions()

                                    {

                                        CancellationToken = cancel.Token

                                    }

                                    , (x) =>

                                    {

                                        Console.WriteLine(x);

                                    });

    }

    catch (Exception ex)

    {

        Console.WriteLine(ex.Message);

    }

 


 

执行结果:

 0

1

2

3

25

4

26

27

50

5

Operation was canceled!

已取消该操作。

 

 

取消正在执行的任务

    当需要根据程序的环境来决定正在执行的并发任务是否要继续执行时,可以用这段代码来解决。

       

 //取消正在执行的Task

        var cancel = new CancellationTokenSource();

        cancel.Token.Register(

            ()=>Console.WriteLine("Operation was cancel")

            );

 

        new Task(() =>

        {

            Thread.Sleep(100);

            cancel.Cancel();

        }).Start();

 

        TaskFactory taskFactory = new TaskFactory(cancel.Token);

 

        Task myTask= taskFactory.StartNew(

            new Action<object>(

                (f) =>

                {

                    for (int i = 1; i <= 100; i++)

                    {

                        CancellationToken token = (f as TaskFactory).CancellationToken;

                        if (token.IsCancellationRequested)

                        {

                            token.ThrowIfCancellationRequested();

                            break;

                        }

                        Console.WriteLine(string.Format("Current Loop index is {0}", i));

 

                        Thread.Sleep(20);

                    }

                }

                ),taskFactory,cancel.Token);

 

        try

        {

            myTask.Wait();

        }

        catch (Exception ex)

        {

            Console.WriteLine(ex.Message);

        }

 


 

执行结果:

 Current Loop index is 1

Current Loop index is 2

Current Loop index is 3

Operation was cancel

发生一个或多个错误。


 

 

Barieer(对数据分块进行处理)

  

class MyBarrier

    {

        public static IEnumerable<string> FillData(int size)

        {

            List<string> data = new List<string>(size);

            Random r = new Random();

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

            {

                data.Add(GetString(r));

            }

            return data;

        }

        //返回长度为6的小写字母

        public static string GetString(Random r)

        {

            StringBuilder sb = new StringBuilder();

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

            {

                sb.Append((char)(r.Next(26) + 97));

            }

            return sb.ToString();

        }

 

        public static int[] CalculationInTask(object p)

        {

            var p1 = p as Tuple<int, int, Barrier, List<string>>;

            Barrier barrier = p1.Item3;

            List<string> data = p1.Item4;

 

            int start = p1.Item1 * p1.Item2;

            int end = start + p1.Item2;

 

            Console.WriteLine("Task {0}:partition from {1} to {2}",Task.CurrentId,start,end);

            int[] charCount = new int[26];

 

            for (int j = start; j < end; j++)

            {

                char c = data[j][0];

                charCount[c - 97]++;

            }

            Console.WriteLine("Calculation completed from task {0}.{1} times a,{2} times z", Task.CurrentId, charCount[0], charCount[25]);

            barrier.RemoveParticipant();

            Console.WriteLine("Task {0} removed from barrier,remaining participants {1}", Task.CurrentId, barrier.ParticipantsRemaining);

            return charCount;

        }

 

        public static void Go()

        {

            const int numberTasks = 2;

            const int partitionSize = 1000000;

            var data = new List<string>(FillData(partitionSize * numberTasks));

 

            var barrier = new Barrier(numberTasks + 1);

 

            var taskFactory = new TaskFactory();

            var tasks = new Task<int[]>[numberTasks];

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

            {

                tasks[i] = taskFactory.StartNew<int[]>(CalculationInTask,

                    Tuple.Create(i, partitionSize, barrier, data));

            }

 

            barrier.SignalAndWait();

            var resultCollection = tasks[0].Result.Zip(tasks[1].Result, (c1, c2) =>

            {

                return c1 + c2;

            });

 

            char ch = 'a';

            int sum = 0;

            foreach (var x in resultCollection)

            {

                Console.WriteLine("{0}, count: {1}", ch++, x);

                sum += x;

            }

 

            Console.WriteLine("main finished {0}", sum);

            Console.WriteLine("remaining {0}, phase {1}", barrier.ParticipantsRemaining, barrier.CurrentPhaseNumber);

 

        }

 

 

    }

 


 

调用代码:

  

  /Barrier类

    MyBarrier.Go();//传说可以将任务进行分块处理的类


 

执行结果:

 Task 1:partition from 0 to 1000000

Task 2:partition from 1000000 to 2000000

Calculation completed from task 1.38040 times a,38365 times z

Task 1 removed from barrier,remaining participants 1

Calculation completed from task 2.38621 times a,38212 times z

Task 2 removed from barrier,remaining participants 1

a, count: 76661

b, count: 77683

c, count: 77014

d, count: 77177

e, count: 76848

f, count: 77223

g, count: 77168

h, count: 77175

i, count: 77223

j, count: 77036

k, count: 77313

l, count: 76620

m, count: 76428

n, count: 76663

o, count: 76871

p, count: 77101

q, count: 76810

r, count: 76714

s, count: 76527

t, count: 76599

u, count: 76957

v, count: 76921

w, count: 76766

x, count: 77037

y, count: 76888

z, count: 76577

main finished 2000000

remaining 1, phase 1

 

Timer类

   一个计时器,定时触发。

var myTimer = new System.Timers.Timer(1000);

myTimer.Elapsed += new System.Timers.ElapsedEventHandler(

(o, oo) => Console.WriteLine("trigger"));

myTimer.Start();

Thread.Sleep(10000);

myTimer.Stop();


 

执行结果:

 trigger

trigger

trigger

trigger

trigger

trigger

trigger

trigger

trigger

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值