Unity C# 之 Task、async和 await 、Thread 基础使用的Task的简单整理

news2024/11/16 10:43:20

Unity C# 之 Task、async和 await 、Thread 基础使用的Task的简单整理

目录

Unity C# 之 Task、async和 await 、Thread 基础使用的Task的简单整理

一、Task、async和 await 、Thread 基础概念

1、线程,多线程

2、Task

 3、async (await )

二、Task 的基础使用,Task 的创建 和 启动

1、创建并运行一个Task

2、创建有返回值的 Task

3、Task提供了 task.RunSynchronously()用于同步执行Task任务

三、Task的阻塞方法(Wait/WaitAll/WaitAny)

1、Thread 阻塞主线程方法 : thread.Join()方法

2、Task提供了 Wait/WaitAny/WaitAll 方法,可以更方便地控制线程阻塞

四、Task的延续操作(WhenAny/WhenAll/ContinueWith)

1、Task 的延续操作(WhenAny/WhenAll/ContinueWith)

 2、Task.Factory 的延续操作(WhenAny/WhenAll/ContinueWith)

五、Task 的任务取消(CancellationTokenSource)

1、Thread 的任务取消

 2、Task 的任务取消

3、 CancellationTokenSource  中 source.Token.Register 和 source.CancelAfter(XXXXms)

 五、异步方法(async/await)

六、Task、async和 await 、Thread 简单小结


一、Task、async和 await 、Thread 基础概念

1、线程,多线程

线程(Thread)是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进程的主线程。

在.NET应用程序中,都是以Main()方法作为入口的,当调用此方法时系统就会自动创建一个主线程。线程主要是由CPU寄存器、调用栈和线程本地存储器(Thread Local Storage,TLS)组成的

CPU寄存器主要记录当前所执行线程的状态,调用栈主要用于维护线程所调用到的内存与数据,TLS主要用于存放线程的状态信息。

多线程:可以同时完成多个任务;可以使程序的响应速度更快;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务;可以随时停止任务;可以设置每个任务的优先级以优化程序性能。

class Program
    {
        static void Main(string[] args)
        {
            //创建无参的线程
            Thread thread1 = new Thread(new ThreadStart(Thread1));
            //调用Start方法执行线程
            thread1.Start();

            Console.ReadKey();
        }

        /// <summary>
        /// 创建无参的方法
        /// </summary>
        static void Thread1()
        {
            Console.WriteLine("这是无参的方法");
        }
    }

2、Task

Task 是在ThreadPool的基础上推出的,我们简单了解下ThreadPool。

  • ThreadPool中有若干数量的线程,如果有任务需要处理时,会从线程池中获取一个空闲的线程来执行任务,任务执行完毕后线程不会销毁,而是被线程池回收以供后续任务使用。
  • 当线程池中所有的线程都在忙碌时,又有新任务要处理时,线程池才会新建一个线程来处理该任务
  • 如果线程数量达到设置的最大值,任务会排队,等待其他任务释放线程后再执行。
  • 线程池能减少线程的创建,节省开销,如下看一个ThreadPool的使用
 static void Main(string[] args)
 {
       for (int i = 1; i <=10; i++)
       {
                //ThreadPool执行任务
                ThreadPool.QueueUserWorkItem(new WaitCallback((obj) => {
                    Console.WriteLine($"第{obj}个执行任务");
                }),i);
       }
     Console.ReadKey();
}

上边的代码通过ThreadPool执行了10个任务,执行结果为

 3、async (await )

async  异步主要用于修饰方法。

当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法;

当一个方法被调用时,立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法。

异步的好处在于非阻塞(调用线程不会暂停执行去等待子线程完成),因此我们把一些不需要立即使用结果、较耗时的任务设为异步执行,可以提高程序的运行效率。

C# 中的 async 和 await 关键字,异步编程非常流行。

1)当我们在处理 UI 时,在点击按钮时,我们使用了一个长时间运行的方法,比如读取一个大文件或其他需要很长时间的东西

2)在这种情况下,整个应用程序必须等待完成整个任务。

3)换句话说,如果同步应用程序中的任何进程被阻塞,整个应用程序都会被阻塞,我们的应用程序会停止响应,直到整个任务完成。

异步编程在这种情况下非常有用。通过使用异步编程,应用程序可以继续进行不依赖于整个任务完成的其他工作。

net4.0在ThreadPool的基础上推出了Task类,微软极力推荐使用Task来执行异步任务,现在C#类库中的异步方法基本都用到了Task;

net5.0推出了async/await,让异步编程更为方便。

二、Task 的基础使用,Task 的创建 和 启动

我们知道了ThreadPool的弊端:

(1)我们不能控制线程池中线程的执行顺序,

(2)也不能获取线程池内线程取消/异常/完成的通知。

net4.0在ThreadPool的基础上推出了Task

(1)Task拥有线程池的优点

(2)同时也解决了使用线程池不易控制的弊端

1、创建并运行一个Task

首先看一下怎么去创建并运行一个Task,Task的 创建 和 启动 执行的方式有如下三种:

  • Task task = new Task(); task.Start();
  • Task task = Task.Factory.StartNew();
  • Task task = Task.Run();
 		 static void Main(string[] args)
        {
            //1.new方式实例化一个Task,需要通过Start方法启动
            Task task = new Task(() =>
            {
                Thread.Sleep(100);
                Console.WriteLine($"hello, task1的线程ID为{Thread.CurrentThread.ManagedThreadId}");
            });
            task.Start();

            //2.Task.Factory.StartNew(Action action)创建和启动一个Task
            Task task2 = Task.Factory.StartNew(() =>
              {
                  Thread.Sleep(100);
                  Console.WriteLine($"hello, task2的线程ID为{ Thread.CurrentThread.ManagedThreadId}");
              });

            //3.Task.Run(Action action)将任务放在线程池队列,返回并启动一个Task
            Task task3 = Task.Run(() =>
              {
                  Thread.Sleep(100);
                  Console.WriteLine($"hello, task3的线程ID为{ Thread.CurrentThread.ManagedThreadId}");
              });
            Console.WriteLine("执行主线程!");
            Console.ReadKey();
        }

运行结果如下,我们看到先打印"执行主线程",然后再打印各个任务,说明了Task不会阻塞主线程:

2、创建有返回值的 Task

上边的代码中 Task 都没有返回值,我们也可以创建有返回值的 Task,用法和没有返回值的基本一致,我们简单修改一下上边的栗子,代码如下:

 Task<数据类型>,task.Result 获取结果

值得注意的是 :task.Resut获取结果时会阻塞线程,即如果task没有执行完成,会等待task执行完成获取到Result,然后再执行后边的代码

  • Task<string> task = new Task(); task.Start();
  • Task<string> task = Task.Factory.StartNew();
  • Task<string> task = Task.Run();
         static void Main(string[] args)
        {
            //1.new方式实例化一个Task,需要通过Start方法启动
            Task<string> task = new Task<string>(() =>
            {
                return $"hello, task1的ID为{Thread.CurrentThread.ManagedThreadId}";
            });
            task.Start();

            //2.Task.Factory.StartNew(Func func)创建和启动一个Task
           Task<string> task2 =Task.Factory.StartNew<string>(() =>
            {
                return $"hello, task2的ID为{ Thread.CurrentThread.ManagedThreadId}";
            });

            //3.Task.Run(Func func)将任务放在线程池队列,返回并启动一个Task
           Task<string> task3= Task.Run<string>(() =>
            {
                return $"hello, task3的ID为{ Thread.CurrentThread.ManagedThreadId}";
            });

            Console.WriteLine("执行主线程!");
            Console.WriteLine(task.Result);
            Console.WriteLine(task2.Result);
            Console.WriteLine(task3.Result);
            Console.ReadKey();
        }

运行结果如下:

3、Task提供了 task.RunSynchronously()用于同步执行Task任务

上边的所有代码中Task的执行都是异步的,不会阻塞主线程。有些场景下我们想让Task同步执行怎么办呢?Task提供了 task.RunSynchronously()用于同步执行Task任务

  • Task task = new Task(); task.RunSynchronously();
        static void Main(string[] args)
        {
            Task task = new Task(() =>
            {
                Thread.Sleep(100);
                Console.WriteLine("执行Task结束!");
            });
            //同步执行,task会阻塞主线程
            task.RunSynchronously();
            Console.WriteLine("执行主线程结束!");
            Console.ReadKey();
        }

运行结果如下:

三、Task的阻塞方法(Wait/WaitAll/WaitAny)

1、Thread 阻塞主线程方法 : thread.Join()方法

Thread的 Join 方法 可以阻塞调用线程,但是有一些弊端:

如果我们要实现很多线程的阻塞时,每个线程都要调用一次Join方法;

如果我们想让所有的线程执行完毕(或者任一线程执行完毕)时,立即解除阻塞,使用Join方法不容易实现。

参考代码如下

          static void Main(string[] args)
        {
            Thread th1 = new Thread(() => {
                Thread.Sleep(500);
                Console.WriteLine("线程1执行完毕!");
            });
            th1.Start();
            Thread th2 = new Thread(() => {
                Thread.Sleep(1000);
                Console.WriteLine("线程2执行完毕!");
            });
            th2.Start();
            //阻塞主线程
            th1.Join();
            th2.Join();
            Console.WriteLine("主线程执行完毕!");
            Console.ReadKey();
        }

运行结果如下:

2、Task提供了 Wait/WaitAny/WaitAll 方法,可以更方便地控制线程阻塞

  • Task.Wait() 表示等待task执行完毕,功能类似于thead.Join();
  • Task.WaitAll(Task[] tasks) 表示只有所有的task都执行完成了再解除阻塞;
  • Task.WaitAny(Task[] tasks)表示只要有一个task执行完毕就解除阻塞;

参考代码如下:

        static void Main(string[] args)
        {
            Task task1 = new Task(() => {
                Thread.Sleep(500);
                Console.WriteLine("线程1执行完毕!");
            });
            task1.Start();
            Task task2 = new Task(() => {
                Thread.Sleep(1000);
                Console.WriteLine("线程2执行完毕!");
            });
            task2.Start();
            //阻塞主线程。task1,task2都执行完毕再执行主线程
            //执行【task1.Wait();task2.Wait();】可以实现相同功能
            Task.WaitAll(new Task[] { task1, task2 });
            Console.WriteLine("主线程执行完毕!");
            Console.ReadKey();
        }

运行结果如下

四、Task的延续操作(WhenAny/WhenAll/ContinueWith)

1、Task 的延续操作(WhenAny/WhenAll/ContinueWith)

上边的 Wait/WaitAny/WaitAll 方法返回值为 void,这些方法单纯的实现阻塞线程

我们现在想:让所有 task 执行完毕 (或者任一task执行完毕) 后,开始执行后续操作,怎么实现呢?

这时就可以用到WhenAny/WhenAll方法了,这些方法执行完成返回一个task实例。

  • task.WhenAll(Task[] tasks) 表示所有的task都执行完毕后再去执行后续的操作
  • task.WhenAny(Task[] tasks) 表示任一task执行完毕后就开始执行后续操作

参考代码如下:

        static void Main(string[] args)
        {
            Task task1 = new Task(() => {
                Thread.Sleep(500);
                Console.WriteLine("线程1执行完毕!");
            });
            task1.Start();
            Task task2 = new Task(() => {
                Thread.Sleep(1000);
                Console.WriteLine("线程2执行完毕!");
            });
            task2.Start();
            //task1,task2执行完了后执行后续操作
            Task.WhenAll(task1, task2).ContinueWith((t) => {
                Thread.Sleep(100);
                Console.WriteLine("执行后续操作完毕!");
            });

            Console.WriteLine("主线程执行完毕!");
            Console.ReadKey();
        }

运行结果如下:

 2、Task.Factory 的延续操作(WhenAny/WhenAll/ContinueWith)

上边的栗子也可以通过 Task.Factory.ContinueWhenAll(Task[] tasks, Action continuationAction)和 Task.Factory.ContinueWhenAny(Task[] tasks, Action continuationAction) 来实现

修改上边代码如下

        static void Main(string[] args)
        {
            Task task1 = new Task(() => {
                Thread.Sleep(500);
                Console.WriteLine("线程1执行完毕!");
            });
            task1.Start();
            Task task2 = new Task(() => {
                Thread.Sleep(1000);
                Console.WriteLine("线程2执行完毕!");
            });
            task2.Start();
            //通过TaskFactroy实现
            Task.Factory.ContinueWhenAll(new Task[] { task1, task2 }, (t) =>
            {
                Thread.Sleep(100);
                Console.WriteLine("执行后续操作");
            });

            Console.WriteLine("主线程执行完毕!");
            Console.ReadKey();
        }

运行结果不变,如下

五、Task 的任务取消(CancellationTokenSource)

1、Thread 的任务取消

在Task前我们执行任务采用的是Thread,Thread怎么取消任务呢?

一般流程是:

  • 1)设置一个变量来控制任务是否停止,如设置一个变量isStop
  • 2)然后线程轮询查看isStop,如果isStop为true就停止

参考代码如下:

        static void Main(string[] args)
        {
            bool isStop = false;
            int index = 0;
            //开启一个线程执行任务
            Thread th1 = new Thread(() =>
            {
                while (!isStop)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"第{++index}次执行,线程运行中...");
                }
            });
            th1.Start();
            //五秒后取消任务执行
            Thread.Sleep(5000);
            isStop = true;
            Console.ReadKey();
        }

运行结果如下

 2、Task 的任务取消

Task中有一个专门的类 CancellationTokenSource 来取消任务执行

还是使用上边的例子,调整代码如下

        static void Main(string[] args)
        {
            CancellationTokenSource source = new CancellationTokenSource();
            int index = 0;
            //开启一个task执行任务
            Task task1 = new Task(() =>
            {
                while (!source.IsCancellationRequested)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"第{++index}次执行,线程运行中...");
                }
            });
            task1.Start();
            //五秒后取消任务执行
            Thread.Sleep(5000);
            //source.Cancel()方法请求取消任务,IsCancellationRequested会变成true
            source.Cancel();
            Console.ReadKey();
        }

程序运行的效果不变,如下

3、 CancellationTokenSource  中 source.Token.Register 和 source.CancelAfter(XXXXms)

CancellationTokenSource 的功能不仅仅是取消任务执行,我们可以使用

  • source.CancelAfter(5000)实现5秒后自动取消任务
  • source.Token.Register(Action action) 可以注册取消任务触发的回调函数,即任务被取消时注册的action会被执行

参考代码如下

        static void Main(string[] args)
        {
            CancellationTokenSource source = new CancellationTokenSource();
            //注册任务取消的事件
            source.Token.Register(() =>
            {
                Console.WriteLine("任务被取消后执行xx操作!");
            });

            int index = 0;
            //开启一个task执行任务
            Task task1 = new Task(() =>
            {
                while (!source.IsCancellationRequested)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine($"第{++index}次执行,线程运行中...");
                }
            });
            task1.Start();
            //延时取消,效果等同于Thread.Sleep(5000);source.Cancel();
            source.CancelAfter(5000);
            Console.ReadKey();
        }

运行结果如下

 五、异步方法(async/await)

在 C# 5.0 中出现的 async 和 await ,让异步编程变得更简单。

此方法利用了 .NET Framework 4.5 及更高版本、.NET Core 和 Windows 运行时中的异步支持。

编译器可执行开发人员曾进行的高难度工作,且应用程序保留了一个类似于同步代码的逻辑结构。

  • async 用在方法定义前面,await只能写在带有async标记的方法中。
  • 注意await异步等待的地方,await后面的代码和前面的代码执行的线程可能不一样
  • async关键字创建了一个状态机,类似yield return 语句;await会解除当前线程的阻塞,完成其他任务

这里实现同步异步读取文件内容的方式。

我们可以看到异步读取代码和同步读取代码基本一致。async/await让异步编码变得更简单,我们可以像写同步代码一样去写异步代码。

注意一个小问题:异步方法中方法签名返回值为Task,代码中的返回值为T。

代码中GetContentAsync的签名返回值为Task,而代码中返回值为string。牢记这一细节对我们分析异步代码很有帮助。

异步方法签名的返回值有以下三种:

  • Task:如果调用方法想通过调用异步方法获取一个T类型的返回值,那么签名必须为Task;
  • Task:如果调用方法不想通过异步方法获取一个值,仅仅想追踪异步方法的执行状态,那么我们可以设置异步方法签名的返回值为Task;
  • void:如果调用方法仅仅只是调用一下异步方法,不和异步方法做其他交互,我们可以设置异步方法签名的返回值为void,这种形式也叫做“调用并忘记”。

参考代码如下

        static void Main(string[] args)
        {
            //Console.WriteLine(" Environment.CurrentDirectory "+ Environment.CurrentDirectory);
            string content = GetContentAsync(Environment.CurrentDirectory + @"/test.txt").Result;
            //调用同步方法
            //string content = GetContent(Environment.CurrentDirectory + @"/test.txt");
            Console.WriteLine(content);
            Console.ReadKey();
        }
 
        /// <summary>
        /// 异步读取文件内容
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        async static Task<string> GetContentAsync(string filename)
        {

            FileStream fs = new FileStream(filename, FileMode.Open);
            var bytes = new byte[fs.Length];
            //ReadAync方法异步读取内容,不阻塞线程
            Console.WriteLine("开始读取文件");
            int len = await fs.ReadAsync(bytes, 0, bytes.Length);
            string result = Encoding.UTF8.GetString(bytes);
            return result;
        }

        /// <summary>
        /// 同步读取文件内容
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        static string GetContent(string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Open);
            var bytes = new byte[fs.Length];
            //Read方法同步读取内容,阻塞线程
            int len = fs.Read(bytes, 0, bytes.Length);
            string result = Encoding.UTF8.GetString(bytes);
            return result;
        }

运行结果如下:

六、Task、async和 await 、Thread 简单小结

最后我们简单记住一些特性,就可以有个较好的理解他们了:

  • 1)async/await是基于Task的
  • 2)而Task是对ThreadPool的封装改进,主要是为了更有效的控制线程池中的线程(ThreadPool中的线程,我们很难通过代码控制其执行顺序,任务延续和取消等等);
  • 3)ThreadPool基于Thread的,主要目的是减少Thread创建数量和管理Thread的成本。
  • 4)async/await Task是C#中更先进的,也是微软大力推广的特性
  • 5)我们在开发中可以尝试使用Task来替代Thread/ThreadPool,处理本地IO和网络IO任务是尽量使用async/await来提高任务执行效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/906383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第四章:树形结构的关联式容器(map+set)

系列文章目录 文章目录 系列文章目录前言1、关联式容器与序列式容器1.1 键值对 2、set的介绍3、multiset的介绍3.1 接口count与容器multiset 4、map的介绍4.1 接口insert4.2 operator[]和at 5、multimap的介绍 前言 根据应用场景的不桶&#xff0c;STL总共实现了两种不同结构的…

PBI 之 Query数据导入、处理

PBI梳理数据流程 首先通过Excel 插件 Power Query、Power Pivot处理数据&#xff0c;然后使用Power Desktop导入处理好的数据进行展示。最后发布到在线网站。 一、导入数据 二、处理数据 如下&#xff0c;进入到Power Query编辑器界面 数据--查询&连接 界面区 界面区右键…

ChatGPT产品发布时间表-了解别人家的创业节奏

ChatGPT产品节点-2023年7月末-长期更新 ChatGPT风靡全球&#xff0c;创造了科技史上的发展奇迹。它可以根据简短的提示生成文章、代码等&#xff0c;极大地提高了生产力。许多大品牌正在尝试利用它来生成广告和营销文字。OpenAI也在此技术上大举投资。以下是ChatGPT产品发布时间…

共创无线物联网数字化新模式|协创数据×企企通采购与供应链管理平台项目成功上线

近日&#xff0c;全球无线物联网领先者『协创数据技术股份有限公司』&#xff08;以下简称“协创数据”&#xff09;SRM采购与供应链项目全面上线&#xff0c;并于近日与企企通召开成功召开项目上线总结会。 基于双方资源和优势&#xff0c;共同打造了物联网特色的数字化采购供…

运动耳机哪款好用、适合运动的耳机推荐

如今&#xff0c;蓝牙耳机不仅是手机的最佳伴侣&#xff0c;也成为了运动爱好者的必备装备。但是&#xff0c;在如此众多的蓝牙耳机中&#xff0c;你是否对选购感到困惑呢&#xff1f;实际上&#xff0c;选择适合运动的蓝牙耳机需要考虑许多因素&#xff0c;如舒适度、稳固性、…

STM32L151C8T6 芯片数据手册

1. 芯片型号含义 2. Flash&#xff1a; 64KB 3. keil 配置ST-Link 烧录程序 4. keil 选择Flash 烧录算法 5. 系统主频 32Mhz 6. 时钟树 clock tree

2009年下半年 软件设计师 上午试卷3

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

数字化赋能高质量施工,成企业创新转型新方向

建筑行业是一个需要投入大量资金、能源消耗大、风险高且劳动力密集的行业&#xff0c;传统施工管理方式存在着“无法实时控制进度、无法实时控制质量、材料浪费、常需返工、安全事件频发”等问题。 为了自身的转型升级&#xff0c;也为了响应国家战略规划落地对建筑行业提出的要…

java 微信小程序授权获取用户手机号码 (完整demo)

1. 前端获取动态令牌 code https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html 2. 后端接收令牌code, 调用微信获取手机号接口 POST https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_tokenACCESS_TOKEN 3. con…

Python操作MongoDB数据库

安装MongoDB库 pip install pymongopython 代码 Author: tkhywang 2810248865qq.com Date: 2023-08-21 10:22:30 LastEditors: tkhywang 2810248865qq.com LastEditTime: 2023-08-21 11:17:45 FilePath: \PythonProject02\MongoDB 数据库.py Description: 这是默认设置,请设置…

JVS低代码:如何触发逻辑并获取外部API数据,接入百度天气查询

了解JVS低代码的小伙伴应该都知道它可以通过API实现数据的入库&#xff0c;但是具体怎么操作的可能还不知道&#xff0c;那今天给大家着重介绍具体的实现流程。 我们以查询百度的天气查询接口&#xff0c;并把对应的数据插入到系统数据模型中为例。 先来看看最后配置实现的效…

记一次异步编程类CompletableFuture使用案例

CompletableFuture 是jdk8进入的一个异步变成工具&#xff0c;可以实现多线程编程。 下面记录了一次&#xff0c;多线程处理处理一个业务的例子&#xff0c;并且要等待所有异步子线程执行完成后&#xff0c;主线程才能继续往下执行。 supplyAsync&#xff1a;异步线程有返回值…

银行数字化转型程度-根据年报词频计算(2012-2021年)

银行数字化转型程度是根据银行年报中的数字化相关词频计算所得的数据。这一数据包括数字化词频关键词、以及数字化转型程度&#xff0c;反映了银行数字化转型的程度和进展情况。从经济学研究的角度来看&#xff0c;这一数据具有重要的参考价值。 首先&#xff0c;银行数字化转…

前端常用的三种加密方式(MD5、base64、sha.js)

作为一名优秀的前端开发工程狮&#xff0c;保障用户的信息安全、密码义不容辞&#xff0c;废话不多说&#xff0c;由我来介绍三种日常开发中经常用到的加密方式。 一、MD5加密 介绍&#xff1a; MD5中文含义为信息-摘要算法5&#xff0c;就是一种信息摘要加密算法&#xff0c…

【数据分享】2013-2023年全国370多个城市逐日空气质量数据(Excel格式/无需转发)

空气质量的好坏反映了空气污染程度&#xff0c;它是依据空气中污染物浓度的高低来判断的。在各项涉及城市环境的研究与实际项目中&#xff0c;城市空气质量都是一个十分重要的指标。那么&#xff0c;去哪里能获取到各城市空气质量的历史数据呢&#xff1f; 之前我们分享了2014…

python连接PostgreSQL 数据库

执行如下命令安装 pip3 install psycopg2 python代码 Author: tkhywang 2810248865qq.com Date: 2023-08-21 11:42:17 LastEditors: tkhywang 2810248865qq.com LastEditTime: 2023-08-21 11:51:56 FilePath: \PythonProject02\PostgreSQL 数据库.py Description: 这是默认设置…

linux系统启动redis

首先进入redis目录 cd /usr/local/redis/redis-7.0.8 输入ll 查看一下 &#xff0c;然后再进入src 目录&#xff0c;找到redis.service文件 输入 ./redis.service 就可以启动了&#xff0c;效果如下图

Mysql系列 - 第1天:mysql基础知识

这是mysql系列第1篇。 本文主要内容 背景介绍 数据库基础知识介绍 mysql的安装 mysql常用的一些命令介绍 SQL分类 背景介绍 我们每天都在访问各种网站、APP&#xff0c;如微信、QQ、抖音、今日头条、腾讯新闻等&#xff0c;这些东西上面都存在大量的信息&#xff0c;这…

小型双轮差速底盘实现悬崖巡检功能

1. 功能说明 本文示例将实现R023样机小型双轮差速底盘悬崖巡检的功能。在小型双轮差速底盘上安装一个检测装置&#xff0c;它可以由1个 近红外传感器 和1个 灰度传感器 组成。近红外传感器可以识别桌面&#xff0c;灰度传感器可以识别“悬崖”&#xff0c;让机器人沿着“悬崖”…

如何快速搭建基于高频数据的因子平台

在因子投研和生产过程中&#xff0c;往往需要基于大量因子进一步加工有状态的复杂指标&#xff0c;比如计算实时 K 线和 MACD、RSI 等。 假设要计算1000个因子&#xff0c;每个因子实现逻辑各不相同&#xff0c;并有特定的如窗口关闭信号、计算窗口边界等配置&#xff0c;重复…