关于C#多线程和异步的一些事。 2024-03-30 学习, C# 暂无评论 ## 多线程(Thread)和异步(Task)的区别 > 多线程是实现异步操作的方式,在需要进行异步操作的地方,会放开当前主线程(不阻塞),IO、网络需要阻塞的延迟操作会在新的线程中执行,执行结果再同步到当前主线程,实现异步。 --- `Thread`和`Task`都可以实现异步 #### Thread > 真正意义上的线程,如果需要做一些轮询操作,可以在线程中`while(true){轮询}` ##### Thread.Sleep(时间) 让当前**线程** 阻塞当前线程多少时间,单位毫秒, 可以理解成在异步操作里的 `await Task.Delay(时间)` #### Task ★ > 可以理解成轻量级的`Thread`, Task可以被await,`Task`可以定义任务的返回值, ``` C# var tsk1 = Task.Run(() => { Console.WriteLine("等待五秒后"); Thread.Sleep(5000); //Task.Delay(5000) Console.WriteLine($"任务取消{source.Token.IsCancellationRequested}"); }); ``` - 注意事项 `Task.Delay(5000)` 返回值是一个Task,如果不await的话,是不阻塞的,起不到阻塞的作用,如果是有返回值的Task,可以用Task.Result获取返回值,但是当前线程会阻塞。 所以如果换成了`Task.Delay(5000)` 是不会等待的直接会执行下面 - 几乎所有的Task都可以传递cts.Token,用来取消任务,但是,需要注意的是,下面是错误写法(下次别这样写,很捞批) ``` C# var tsk1 = Task.Run(() => { Console.WriteLine("等待五秒后"); Thread.Sleep(5000); //Task.Delay(5000) Console.WriteLine($"任务取消{source.Token.IsCancellationRequested}"); }, cts.Token); ``` 上面的`cts.Token`没有意义,不会对当前的Task生效,需要手动处理 `await Task.Delay(5000,cts.Token)` 如果超时,这行会抛出任务取消的异常,因为里面有封装过。 这种写法是可以取消任务的 ``` C# public async void ctsCancel(CancellationToken token) { try { //直接Run 可以运行,但是发生异常不会进入catch var tsk1 = Task.Run(async () => { await testAction(token); }); //这里会把异常抛出,进入catch await tsk1; } catch (Exception ee) { Console.WriteLine(ee.Message); } } //方法体 private Task testAction(CancellationToken cancellationToken) { return Task.Run(async () => { var ls = Enumerable.Range(1, 100).ToList(); foreach (var item in ls) { cancellationToken.ThrowIfCancellationRequested(); Console.WriteLine(item); await Task.Delay(500); } }); } ``` > token在外部已经进行超时处理了,五秒后会取消, `cancellationToken.ThrowIfCancellationRequested();`自己写的异步方法需要把token传过来,进行判断。 #### Task.ContinueWith() 类似于Js的Then 回调函数 > 这是Task对象的一个方法,可以传一个参数(Action),两个参数(Action,执行条件) 执行条件的是一个枚举,可以点进去看,根据上一步的状态(报错、执行完成),判断是否往下执行。 TaskContinuationOptions.OnlyOnRanToCompletion ``` C# public void ContinueWith() { var tsk = Task.Run(() => { Console.WriteLine("第一层"); Thread.Sleep(1000); Console.WriteLine("第一层等待一秒后"); var num = new Random().Next(1, 20); if (num % 2 == 0) { return num.ToString(); } else { throw new Exception("奇数异常"); } }).ContinueWith(r => { //如果上一个流程有异常,这里是不会执行的,异常也捕捉不到。 Console.WriteLine($"r.Exception==null : {r.Exception == null}"); Console.WriteLine("第二层"); var res = r.Result; return res; }, TaskContinuationOptions.OnlyOnRanToCompletion); try { //这里可以把异常抛出 var res = tsk.Result; Console.WriteLine("任务成功" + res); } catch (Exception ee) { Console.WriteLine("任务取消" + ee.InnerException?.Message); } } ``` #### 小结 > Task.Result和await Task 可以理解成把异步执行的结果拿到当前线程来,如果不拿过来的话,结果、异常都是没办法知晓的,因为不在同一个线程。 所以,在使用Task时候,可以在内部处理可能遇到的异常,多个Task可以用ContinueWith给串起来,在串起来的过程中可以配置往下执行的条件。
Get✔一款优秀的异地组网的软件 ZeroTier 2024-01-15 学习 暂无评论 #### ZeroTier > 我以前咋没发现这个软件这么好用呢,支持全平台,可以异地组网,而且是p2p方式,通过udp打洞的方式实现,支持全平台,缺点就是udp打洞需要网络环境和时间。 1. 在官网注册账号 my.zerotier.com 2. 注册后创建网络,有唯一的识别码,在客户端加入, 3. 等待组网成功 4. 组网成功使用特定的ip就可访问特定的设备 5. 客户端可以结合socat,将下游的服务端口转发到客户端端口,而不需要安装多个客户端 > 可以使用的几个命令 1. `zerotier-cli peers`可以查看当前的所有节点,以及节点的类型 2. `~ info` 可以查看当前是否连接成功
他又开始了,他说他会学的。😒😒😒 2024-01-02 默认分类, 学习, C# 暂无评论 > 起草了一个Erp的项目,立项的初衷是给俺姐用的,但是这可能是个商机,小公司不需要大型Erp,而且价格还贵,或者可以做起来搞个副业。 ##### 采用前后端分离的模式 1. 后端用的.Net6的WebApi框架,尽量的按照主流要求来 2. 前端打算使用Vue3来开发(好像你很熟一样🤣)只做微信小程序 3. 主要功能就是进销存功能,数据统计,财务报表管理等等,对这个也不熟,仅有的知识进行了头脑风暴 ##### 使用拦截器(过滤器) > 对数据进行严格的处理,注释写满!!保证低耦合、可维护性。 ##### 使用依赖注入 > 进一步降低代码的耦合,对定制系统可以更加友好,降低工作量。 ##### 最后 **一定要坚持下去!!!**
一波git的心得正在路上~ 2022-10-29 学习 暂无评论 ## git的一些想法和姿势 > 之前有写过git的使用方法,但是远不止那些,add commit push 直接梭哈,一旦出现冲突根本不会解决(现在也不会😅😅😅) - 基本流程 - `git checkout -b 分支名称` 创建一个新分支 - 在新分支上进行修改 - 如果remote的master**没有**变化,直接`git push origin 分支名称` 把分支上传到remote - 如果remote的master在checkout之后进行**变更**了,先checkout到master `git pull`获取到最新remote代码,在切换到本地的分支,`git rebase master` 对修改的分支进行**变基**,再push到remote,这种情况是没有修改相同文件的情况,不会出现冲突,反之,emmmm可能要手动修改选择保留哪一端代码。 - 涉及到的指令 - `git rebase branchName `把branchName作为父级仓库版本,也可以理解成,把branchName的改动拿到当前分支中来。 - `git checkout -b branchName`把当前的分支作为基本分支,并且迁出。和`git switch -c branchName`是一个意思 - `git checkout branchName` 切换分支,和`git switch branchName`是一个意思 - `git init`和`git init --bare` bare是指创建一个裸仓库,共享仓库的意思,没有.git这个文件夹,提交、切换分支等等,不会改变仓库的本地代码(直接init的话,用`git checkout 分支名` 就会改变本地的代码,所以不适用于公共仓库) - `git branch -a` 显示所有可用的分支 - `git branch -r `显示remote分支 (这个其实不准确,如果pull下来之后,remote中分支被删除,还是会显示出来) - `git remote prune origin`因为上面一个问题,这个可以更新远端仓库的信息,如果删除了,本地也会消失 - `git push --delete 分支名称` 可以删除remote的分支 - 本地代码落后,需要更新本地的其他代码 - `git stash ` 将更改暂存 - `git pull` 更新远端代码 - `git stash pop` 将暂存的代码抛出 > 这样实现更新代码,如果修改了同一个文件可能会出现冲突