在多线程环境中使用 Random 类来生成伪随机数时,很容易出现线程安全问题。例如,当多个线程同时调用 Next 方法时,可能会出现种子被意外修改的情况,导致生成的伪随机数不符合预期。
线程是操作系统能够进行运算调度的最小单位,操作系统线程进一步被封装成托管的Thread对象,手工创建并管理Thread对象已经成为了所能做到的对线程最细粒度的控制了。后来我们有了ThreadPool,可以更加方便地以池化的方式来使用线程。最后,Task诞生,它结合async/await关键字给与我们完美异步编程模式。但这一切让我们的编程体验越来越好,但是离线程的本质越来越远。被系列文章从“执行上下文传播”这个令开发者相对熟悉的角度来聊聊重新认识我们似乎已经很熟悉的主题。
在单核计算机中,CPU 是独占的,内存是共享的,这时候运行一个程序的时候是没有问题。但是运行多个程序的时候,为了不发生一个程序霸占整个 CPU 不释放的情况(如一个程序死循环无法结束了,那么其他程序就没有机会运行了),就需要开发者给不同程序划分不同的执行时间。为了避免不同程序之间互相操作数据或代码,导致程序被破坏的情况,就需要开发者给程序划分独立的内存范围。也就是程序需要开发者进行调度以及和划分独立的内存空间。
我们知道Random不是线程安全的,所以如果要在多线程下使用的话,就必须考虑线程安全问题。部分开发人员会在使用的时候才去new 一个Random对象,但是这样做首先是代码不够简洁,并且会创建过多的Random对象,那么怎么解决这个问题呢?比较简单且常见的方法是加锁:
通过ILSpy反编译查看可以知道,lock是个语法糖,编译后其实是Monitor.Enter 和 Monitor.Exit 的封装。
在之前的文章中,我们介绍了 dotnet 在字符串拼接时可以使用的一些性能优化技巧。比如:
前篇说到了使用异步线程来实现数据的预加载,以提高系统性能。 这样的操作一般是在客户端执行,用以减少用户的等待时间。客户端发送多次异步请求,到达服务端后,如果服务端不支持多线程处理操作,线性处理各个请求,必然导致客户端的异步请求变得没有意义。 大家肯定会说,谁会把服务端设计成单线程的啊,那不是明显的错误吗?是的!但是我们的系统使用了CSLA来作为实现分布式的框架,而它的服务端程序却只能支持单线程……这个问题我们一直想解决,但是查过CSLA官方论坛,作者说由于GlobalContext和
这是一段 MSDN 官方的 MD5 示例,例子很简单且很容易理解。但是,这个例子也有很多的问题,首先上例至少创建了 3 个临时缓存区!且每次执行 GetMd5Hash 都会创建一个 MD5 实例,并在方法执行完成后释放它。这些都造成了很大的系统资源浪费和增加了 GC 的压力。
上一篇讲到将WPF的窗口转为WinForm窗口需要注意的问题,这里给出了另一种解决方案,闲话不说,请看代码: //============================================================================== // File Name : WpfModalDialogFixer.cs // // Copyright (C) 2010 GrapeCity Inc. All rights reserved. // // Distribu
在 dotnet 程序提供了一个好用的特性,可以让字段作为线程的静态字段,也就是在相同线程的所有代码访问的静态字段是相同对象,但不同线程访问的时候是不同的
在 WPF 调试中,对于 DispatcherTime 定时器的执行,没有直观的调试方法。本文来告诉大家如何在 WPF 中调试当前主线程有多少个 DispatcherTime 在运行
垃圾回收解放了手工管理对象的工作,提高了程序的健壮性,但副作用就是程序代码可能对于对象创建变得随意。
在 WPF 调试中,对于 DispatcherTimer 定时器的执行,没有直观的调试方法。本文来告诉大家如何在 WPF 中调试当前主线程有多少个 DispatcherTimer 在运行
假如有一个设备,采用UDP组播协议,在正常通讯情况下通过网络给你发送数据,注意的是,不管通道有没有通都会发出数据但是对应的关键标识没有,设备每100ms发送一次。
相信大家对TransactionScope都比较熟悉。通过TransactionScope,我们可以很容易地将一组操作纳入同一个事务中;或者说TransactionScope创建一个基于事务的上下文范围,在这个范围内共享一个相同的环境事务(Ambient Transaction)。我个人觉得这体现了一种可以重用的模式,即本篇文章介绍的Context+ContextScope模式,这种模式旨在一定范围内创建一个可以共享的上下文信息。
下面的一些基本概念可能和.NET的联系并不大,但对于掌握.NET中的多线程开发来说却十分重要。我们在开始尝试多线程开发前,应该对这些基础知识有所掌握,并且能够在操作系统层面理解多线程的运行方式。
What Great .NET Developers Ought To Know (More .NET Interview Questions)
本文主要讲解了如何利用.NET 6中的Task Parallel Library实现线程池,包括创建、执行、完成和扩展线程池的方法。同时,还介绍了如何使用异步编程和动态编译技术实现多线程和异步编程,并通过示例代码进行了详细的展示。
net同僚对于async和await的话题真的是经久不衰,这段时间又看到了关于这方面的讨论,最终也没有得出什么结论,其实要弄懂这个东西,并没有那么复杂,简单的从本质上来讲,就是一句话,async 和await异步的本质就是状态机+线程环境上下文的流转,由状态机向前推进执行,上下文进行环境切换,在状态机向前推进的时候第一次的movenext会将当前线程的环境上下文保存起来,然后由TaskScheduler调度是否去线程池拿新线程执行这个task,等到后续推进到最后的movenext的时候,里面设置好结果,异常之后,回调则需要运行在调用await之前的环境上下文中去,这里说的是环境上下文,而并非是线程,所以当前环境上下文在await之前是A线程的上下文,在遇到await结束之后可能是B线程的环境上下文,并且异步是异步,线程是线程,异步不一定多线程,这两个不是等价的,针对async和await的源码刨析可以看一下之前写的博客https://www.cnblogs.com/1996-Chinese-Chen/p/15594498.html,这篇文章针对源码讲了一部分,可能不是很明了,只讲了async await执行的一个顺序对于环境上下文没有过多的描述,接下来,我会讲一些环境上下文,同步上下文的知识,以及在cs程序中,框架对于同步上下文的封装。
https://www.cnblogs.com/Can-daydayup/p/17980851
在本人的.NET面向上下文、AOP架构模式(概述)一文中,我们大概了解了上下文如何辅助对象在运行时的管理。在很多时候我们急需在运行时能把对象控制在一定的逻辑范围内,在必要的时候能让他们体现出集中化的概念,如人群、车辆、动物等等。而Context与AOP有着密切的联系,Context表示逻辑抽象的范围而AOP描述了在这个逻辑范围内如何进行控制。其实这两者都是设计模式外的设计模式,与具体的技术实现无关。[王清培版权所有,转载请给出署名]
.NET Core中加入了本地队列,加入了本地队列,降低了锁竞争,并提高了线程的利用率。
我在7月份到了家新公司,要维护一个在原来.net1.1上的系统。我进去一看代码就傻了眼了,满屏的SQL语句,看得脑袋嗡嗡的.但是苦于.net1.1,又不敢大动直接上其他的orm..顺便 Castle Activerecord 的.net1.1版还真用不来,于是一怒之下,决定自己动手,自己搞一个,遂自己瞎糊弄了一个,在项目中用了,感觉良好,嘿嘿,先不多说,把代码统统拷上来: //wxy create at 2008-8-31 //自己实现了一个简易的ORM工具,方便数据库操作 //关键是我实在不想写那些 //
在《使用篇》中我们谈到扩展的验证编程方式,并且演示了本解决方案的三大特性:消息提供机制的分离、多语言的支持和多验证规则的支持,我们现在来看看这样的验证解决方案最终是如何实现的。 目录: 一、为验证创建一个上下文:ValidatorContext 二、通过自定义ActionInvoker在进行操作执行之前初始化上下文 三、为Validator创建基类:ValidatorBaseAttribute 四、通过自定义ModelValidatorProvider
在很多情况下我们具有这样的需求:为一组相关的操作创建一个执行上下文并提供一个共享的数据容器,而不是简单地定义一个全局变量,或者将数据通过参数传来传去。这样的上下文一般具有其生命周期,它们在目标操作开始执行的时候被激活,在执行完成之后被回收。该上下文一般不能跨越多个线程,以避免多个线程操作相同的数据容器造成数据的不一致。针对这个需求,我们写了一个非常简单的例子,有兴趣的朋友可以看看。[源代码从这里下载] 目录 一、ExecutionContext的基本编程方式 二、异步调用的问题
上下文:其实就是一个逻辑上的业务、功能区域。在这个逻辑区域里可以有效的进行管理,算是一种制度的约束,也可以理解为某种范围类的数据共享。
EntLib的异常处理应用块(Exception Handling Application Block)是一个不错的异常处理框架,它使我们可以采用配置的方式来定义异常处理策略。而ASP.NET MVC是一个极具可扩展开发框架,在这篇文章中我将通过它的扩展实现与EntLib的集成,并提供一个完整的解决异常处理解决方案。[源代码从这里下载] 目录 一、基本异常处理策略 二、通过自定义Action处理异常 三、通过配置的Error View处理异常 四、自定
System.Transactions.TransactionScope为了提供一种非常方便的实现分布式事务的方式,但是在某些情况下为了阻止本地事务向分布式事务提升,我们只能通过DbTransaction进行事务控制。在进行数据库操作的时候,我们经常会遇到这样的事务场景:当某个方法单独执行的时候,它应该在一个单一的DbTransaction中执行;当多个方法一起执行的时候,它们应用共同在DbTransaction中执行。在本篇文章中我们通过对DbTransaction进行封装,提供一种类似于Transact
scribe结构及源码详细分析 1. 整体类关系图 image.png 2. 客户端写日志序列图 image.png 3. 活动及状态图 image.png Scribe活动图 image.png 4. 启动代码详解 image.png 启动过程流程图 (1) 调用setrlimit函数设置能够打开的最大文件数为65535; (2) 调用getopt_long函数解析运行scrib
线程可以被描述为它所处的进程中的一个微进程,它拥有起点,执行的顺序系列和一个终点。
https://www.cnblogs.com/shawshank/p/17390248.html
在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实现对于数据库的快速访问,后来,ORM(Object Relational Mapping,对象关系映射)出现了,我们开始使用 EF、Dapper、NHibernate,亦或是国人的 SqlSugar 代替我们原来的 SqlHelper.cs。通过这些 ORM 工具,我们可以很快速的将数据库中的表与代码中的类进行映射,同时,通过编写 SQL 或是 Lambda 表达式的方式,更加便捷的实现对于数据层的访问。
对async/await的支持已经存在了十多年。它的出现,改变了为 .NET 编写可伸缩代码的方式,你在不了解幕后的情况下也可以非常普遍地使用该功能。
https://www.cnblogs.com/eventhorizon/p/17481757.html
如果没有编码规范,团队中的每个人都按自己的编码风格来。在不久的将来,维护和调试代码将变得不容易。
在即将发布的 .NET 6 runtime 中,默认的线程池实现从 C++ 代码改为了 C#,更方便我们学习线程池的设计了。 https://github.com/dotnet/runtime/tree/release/6.0/src/libraries/System.Threading.ThreadPool
领取专属 10元无门槛券
手把手带您无忧上云