solitaryclown

多线程

2023-04-01
solitaryclown

1. csharp多线程

1.1. csharp5新特性async/await

1.1.1. 性质

  1. async用于修饰方法,表示这是一个异步方法
  2. 具体实现异步是在普通的同步方式调用方法之前加上await关键字
  3. 使用await调用异步方法时,调用它的方法必须加上async关键字,即await只能出现在使用async修饰的方法中

1.1.2. 概念

1.1.2.1. 异步方法

概念:异步方法在完成其工作之前立即返回到调用方法,调用方法可以继续执行后面的操作,如果异步方法有返回结果,调用方法在获取结果时如果异步方法没有完成,调用方法会执行阻塞等待操作。 异步方法的性质:

  1. 方法签名包含async修饰
  2. 返回值为以下三种类型:
    • void:不需要返回值
    • Task:不需要返回值,但可能需要获取方法的状态
    • Task<T>:需要一个T类型的返回值
  3. 方法参数不能为out、ref参数
  4. 方法名约定俗成以”Async”为后缀,如CalculateAsync代表一个异步计算的方法

1.1.3. Example

[assembly: log4net.Config.XmlConfigurator(ConfigFile ="log4net.config",Watch =true)]
namespace _2023_4_1_DownloadDemo
{
    class Program2
    {
        private static ILog log=LogManager.GetLogger("Program2");
        public Program2()
        {
        }
        static void Main(string[] args)
        {
            Task<int> task = CalculateAsync(5, 6);
            //处理其他事情...
            Print();
            log.Info(task.Result);
            Console.ReadKey();
        }
        private static async Task<int> CalculateAsync(int a, int b)
        {
            Func<int> func = () =>
              {
                  log.Info($"Thread:{ Thread.CurrentThread.GetHashCode()}");
                  //这里是一些耗时的操作
                  Thread.Sleep(3000);
                  return GetSum(a, b);
              };
            int sum = await Task.Run(
                func
             );
            return sum;
        }
        private static int GetSum(int a, int b) { return a + b; }

        private static void Print()
        {
            Task.Run(() => {
                log.Info($"Thread:{Thread.CurrentThread.GetHashCode()}");
                log.Info("asasd");
            });
        }
    }
}

输出:

2023-04-01 11:27:59,949 [4] INFO  - Thread:4
2023-04-01 11:27:59,949 [5] INFO  - Thread:5
2023-04-01 11:27:59,957 [5] INFO  - asasd
2023-04-01 11:28:02,970 [1] INFO  - 11

1.1.4. Task.Run()方法

Task.Run()是一个用来执行自定义异步任务的静态方法,参数是ActionFunc这些委托类型。

1.1.5. 取消异步任务

System.Threading.Tasks中有两个类为此目的设计:CancellationTokenCancellationTokenSource

  • CancellationToken对象包含一个任务是否应被取消的信息
  • 拥有CancellationToken对象的任务定期检查token状态,如果属性IsCancellationRequested为true,任务停止操作并返回
  • CancellationToken不可逆,一旦属性IsCancellationRequested设置成true,就不能更改
  • CancellationTokenSource对象创建可以分配给不同任务的CancellationToken对象,任何持有CancellationTokenSource的对象都可以调用其Cancel()方法,这会将CancellationToken对象的属性IsCancellationRequested为true

Example

  public class Program4
    {
        private static ILog log = LogManager.GetLogger("Program4");
        public static void Run()
        {
            CancellationTokenSource tokenSource = new CancellationTokenSource();
            CancellationToken token = tokenSource.Token;

            MyClass mc = new MyClass();
            Task t=mc.RunAsync(token);

            Thread.Sleep(3000);
            tokenSource.Cancel();

            t.Wait();
            log.Info($"was cancelled:{token.IsCancellationRequested}");

            Console.Read();
        }

        class MyClass
        {
            internal async Task RunAsync(CancellationToken token)
            {
                if (token.IsCancellationRequested)
                { return; }
                await Task.Run(() => CycleMethod(token), token);
            }
            private void CycleMethod(CancellationToken token)
            {
                log.Info("Starting cycle");
                const int max = 5;
                for (int i = 1; i <= max; i++)
                {
                    if (token.IsCancellationRequested)
                    {
                        return;
                    }
                    Thread.Sleep(1000);
                    log.Info($"{i} of {max} iterations completed.");
                }
            }
        }
    }

输出:

2023-04-01 15:18:14,734 [4] INFO  - Starting cycle
2023-04-01 15:18:15,750 [4] INFO  - 1 of 5 iterations completed.
2023-04-01 15:18:16,753 [4] INFO  - 2 of 5 iterations completed.
2023-04-01 15:18:17,759 [4] INFO  - 3 of 5 iterations completed.
2023-04-01 15:18:17,760 [1] INFO  - was cancelled:True

BackgroundWorker

async/await适合处理在后台完成的不相关的小任务,如果后台任务需要持续执行并且要和主线程通信,这个时候的异步适合使用BackgroundWorker


上一篇 2D匹配

Comments

Content