定制网站的价格低,仿门户网站多功能js相册画廊源码 支持缩略小图浏览,搜什么关键词能找到网站,网页字体导入wordpress“发现问题的能力#xff0c;运用技术解决问题的能力#xff0c;是一个技术人成长的关键”图片故事#xff1a;洋姜的花#xff0c;拍摄于2022年7月23日#xff0c;地点#xff1a;北京奥林匹克森林公园 #xff0c;摄影师#xff1a;刘先生概要#xff1a;使用C#发起…“发现问题的能力运用技术解决问题的能力是一个技术人成长的关键”图片故事洋姜的花拍摄于2022年7月23日地点北京奥林匹克森林公园 摄影师刘先生概要使用C#发起多线程任务十分简单本文旨在汇总多线程编程的注意事项重点不在于如何发起多线程主要内容如下控制线程并发数量界定共享资源加锁并控制锁范围子线程异常处理未完成任务取消希望对小伙伴儿们有所帮助01—控制线程并发数量多线程以多任务并行的方式加快业务处理速度但如果线程数量超出了系统的承载能力反倒会造成系统整体性能下降如何合理地控制线程并发数量是多线程开发的关键。推荐采用信号量机制可以在线程总数未知的情况下有效地控制并发线程数量并且以瀑布流的形式连续执行后续线程逻辑清晰可控执行性能高效。基础代码逻辑如下//semaphoreCount是设定的可并行运行的最大线程数量
//taskCount是需要发起的线程的数量
using (Semaphore semaphore new Semaphore(semaphoreCount, semaphoreCount))
{var woker new Worker();Task[] tasks new Task[taskCount];for (int step 0; step taskCount; step) { //获取一个信号量如果所有信号量都已使用则等待直到一个被释放 semaphore.WaitOne(); //获得信号量之后才能发起子线程 tasks[step] Task.Factory.StartNew((data) { woker.Work(data); }, innerData).ContinueWith((task) { //线程完成释放信号量 semaphore.Release(); }); } //...
}简单来说是由于分时操作系统多任务之间存在线程上下文切换有兴趣的同学可以尝试一下一次性启动2000个以上线程查看计算机的资源耗用情况以便有更真切的体会。02—界定共享资源线程共享资源一类是业务本身需要多个子线程共同处理的资源另一类是从性能角度考虑需要被多个子线程共享的资源。以数据查询为例数据库连接是一种昂贵的资源如果每个子线程单独创建数据库连接必然会造成浪费多个线程共用一个数据库连接是更合理的选择因此数据库连接便是共享资源。有兴趣的同学可以测试一下同时启动50个以上线程如果每个线程创建一个数据库连接会造成数据库短时间内无法创建足够连接而报错。03—加锁并控制锁范围对共享资源进行访问时需要加锁保护防止并发错误。对于业务本身处理的共享资源加锁主要是防止数据处理错误对于集合类型的共享资源建议首选System.Collections.Concurrent 命名空间下的集合类型以达到线程安全的目的对于如数据库连接之类的资源加锁是为了防止程序异常如数据库连接、HttpClient对象在一个请求处理完之前是不能被其他线程访问的因此需要加锁确保串行访问是必须的。对于锁对象推荐的写法如下至于是不是要加static 要看具体业务场景静态变量的作用域是整个应用程序如果有两个以上请求同时到达那么在访问到加锁代码块时请求也是串行执行的普通变量的作用域是当前对象锁范围也是在当前对象内请求间相互不影响。readonly object locker new object();04—子线程异常处理概括成一句话是在明确异常处理要做什么的情况下才进行异常处理否则让异常抛出交由外层程序处理即可。参考我上一篇文章异常处理究竟是处理什么多线程下异常处理的不同之处在于子线程内的异常不会直接抛出到主线程而是保存在了Task对象的Exception属性中。因此需要开发小伙伴判断线程状态进行异常处理。基础代码逻辑如下Task.Factory.StartNew((data) { woker.Work(data); }, innerData) .ContinueWith((task) { //判断线程处理状态如果执行失败则抛出异常 if (task.Status TaskStatus.Faulted) { throw task.Exception; } });05—未完成任务取消当某个子线程发生异常之后取消后续相关线程的执行符合绝大多数业务逻辑。取消线程操作需要用到 CancellationTokenSource 类线程启动时注册“取消凭证Token”当某个子线程发生异常后调用CancellationTokenSource的Cancel()方法通知相关线程取消操作。以后会写一篇CancellationToken的详细介绍。基础代码逻辑如下//声明 CancellationTokenSource
using (CancellationTokenSource cancellation new CancellationTokenSource())
{Task[] tasks new Task[taskCount];for (int step 0; step steps; step){semaphore.WaitOne();//注册cancellation.Tokentasks[step] Task.Factory.StartNew((data) { woker.Work(data); }, innerData, cancellation.Token).ContinueWith((task) {if (task.Status TaskStatus.Faulted){//通知取消任务cancellation.Cancel(true);throw task.Exception;}semaphore.Release();});}
}有多线程开发经历的小伙伴可以看一下自己的代码是否有对以上几点的处理。以上内容均来自于我个人的经验总结如有疏漏欢迎小伙伴补充指正。最后说一下对于多线程的认识了解二次元的小伙伴应该知道一个词“结界”线程与结界有很多相似之处一个子线程就相当于一个结界结界内外虽处于同一空间但却属于不同的世界结界阻断了结界内外的联系但又可以相互作用更多相似处小伙伴们自己体会。您的反馈是我坚持的动力欢迎点赞转发关注