Parallel并行之乱用
关于Parallel我也不细说了,一则微软封装的很好用,二来介绍这个的遍地都是。
我要说的是,要想成为一个优秀的标题党,一定要把重点放到别的地方,为了节省大家阅读时间,我先把结论说了,然后再慢慢从头说,愿意往下看的可以看看因果,不愿意看的,也算咱给大家提个醒吧。
结论就是,大家在做单元测试用例的时候一定要用心,这篇随笔是要检讨并警醒下自己并与大家共勉。
据一些我不记得名字的国外权威专家,据说是测试大师级人物研究,测试用例的出现的错误并不比被测试的代码少,我相信大多数人会和我类似,在写代码的时候小心翼翼,但是为代码编写单元测试及用例的时候往往注意力下意识的不那么集中,今天就是这么个情况。可能是缺乏锻炼(我天天打太极拳的。。。)的原因,连续几个晚上由于学习原因睡的比较晚,今天就比较困,然后干了件点题的事。
我写了一个对象ID生成器,以时间戳和顺序号组合,虽然不支持集群,但是目前情况下足够了,然后因为复制数据库的同事坚决不同意将主键的int类型改掉,那怕改成bigint都不同意。。。跑题了。总之,各种限制的情况下出了这么个东西:
//不能再集群情况下使用
public class IDGenerator
{
private static double _seconds = 0;
private static int _sequenceIndex = 0;
private static object _lock = new object();
private static ReaderWriterLockSlim writerLock = new ReaderWriterLockSlim();
private static IDGenerator _instance; private IDGenerator()
{
} public static int NewID
{
get
{
int newID = IDGenerator.Instance.CreateNewID();
return newID;
}
} private int CreateNewID()
{
string id; writerLock.EnterReadLock();
try
{
id = BuildIDAndUpdateSead();
}
finally//保证退出锁
{
writerLock.ExitReadLock();
}
int newID = TypeParseHelper.GetIntValueByString(id);
return newID;
} private string BuildIDAndUpdateSead()
{
double seconds;
bool isEqualSecondsCount;
seconds = InterceptSecondsInTicks(); isEqualSecondsCount = seconds.Equals(_seconds);
if (isEqualSecondsCount)
{
bool isUpperBound = _sequenceIndex == ;
if (isUpperBound)
{
Thread.Sleep();
_sequenceIndex = ;
_seconds++;
}
else
{
Interlocked.Increment(ref _sequenceIndex);
}
}
else
{
_seconds = seconds;
}
string id = _seconds.ToString() + _sequenceIndex.ToString().PadLeft(, '');
return id;
}
private double InterceptSecondsInTicks()
{
DateTime currentDate = DateTime.Now;
long elapsedTicks = (currentDate.Ticks - ConstantGather.BEGIN_STANDARD_TICKS);
TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
double seconds = Math.Floor(elapsedSpan.TotalSeconds);
return seconds;
}
private static IDGenerator Instance
{
get
{
if (_instance != null)
{
return _instance;
}
lock (_lock)
{
if (_instance == null)
{
_instance = new IDGenerator();
}
}
return _instance;
}
}
}
做完了,当然要写点单元测试测试一下,就先写了个同步的,然后写了个异步的,然后写了个并发的
public List<int> GenerateRequisitionIDs()
{
TaskFactory taskFactory = new TaskFactory();
Task<int>[] tasks = new Task<int>[] {
taskFactory.StartNew(() => GenerateRequisitionID()),
taskFactory.StartNew(() => GenerateRequisitionID()),
taskFactory.StartNew(() => GenerateRequisitionID()) }; var query = tasks.Where(t => !t.Result.Equals())
.Select(t => t.Result);
return query.ToList();
}
高潮来了,然后我在单元测试里顺手写了个并行的。。。
Parallel.For(, actual, c =>
{
int id = target.GenerateRequisitionID();
list.AddLast(id);
});
测试结果就不停得出错,我费了很大功夫定位到了出错的位置。。。
string idStr = _seconds.ToString() + "-" + _sequenceIndex.ToString().PadLeft(, '');
这一句是我写了一堆定位错误的代码中的一句,发现了个奇怪的现象,这个字符串赋值后,两边居然是不一样的,而且这一句在排它锁里。。。
并行的用法应该是将一对任务,平均分开,各自做各自的,互相不影响,问题就在于我这生成器是个单例。。。
作为一个敬业的标题党,并发和并行的区别我就不说了,反正连百度都知道的事。。。
最后说一句,单元测试要认真,单元测试的代码哪怕随便玩的也要组织好,不要乱放,不要完全不着边的都测,正常业务里是不会有并行生成ID的场景的,这个测试没有意义,而且,如果看了生成器的代码会发现,由于int32本身的长度问题,我限定了一秒最多能生成999个ID,我需要测的其实不是并行问题,太晚了,思维比较跳跃,就这么着吧,下次长点记性就好了,以上。
Parallel并行之乱用的更多相关文章
- Parallel并行编程初步
Parallel并行编程可以让我们使用极致的使用CPU.并行编程与多线程编程不同,多线程编程无论怎样开启线程,也是在同一个CPU上切换时间片.而并行编程则是多CPU核心同时工作.耗时的CPU计算操作选 ...
- C# IEnumerable,Lambda表达式和 Parallel并行编程的用法
以前一直主要做C++和C方面的项目,对C#不太了解熟悉,但听说不难,也就一直没有在意学习C#方面的知识.今天有个C#项目,需要做些应用的扩展,同时修改一些bug.但看了C#代码,顿时觉得有些不适应了. ...
- Parallel并行编程
Parallel并行编程 Parallel并行编程可以让我们使用极致的使用CPU.并行编程与多线程编程不同,多线程编程无论怎样开启线程,也是在同一个CPU上切换时间片.而并行编程则是多CPU核心同时工 ...
- C# 使用Parallel并行开发Parallel.For、Parallel.Foreach实例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...
- list.stream().parallel() 并行流
https://blog.csdn.net/u011001723/article/details/52794455/ : parallel()其实就是一个并行执行的流.它通过默认的ForkJoin ...
- Stream parallel并行流的思考
1.并行流并不一定能提高效率,就和多线程并不能提高线程的效率一样 因为引入并行流会引起额外的开销,就像线程的频繁上下文切换会导致额外的性能开销一样,当数据在多个cpu中的处理时间小于内核之间的传输时间 ...
- .net Parallel并行使用注意事项
因项目响应过慢,代码优化空间不大,在暂时无法调整系统架构的情况下,只有使用.NET中的TPL解决一些模块耗时过多的问题.但在使用过程中也碰到了一些问题,现在把它写下来,用于备忘. 1. Paralle ...
- .net Parallel并行使用
因项目响应过慢,代码优化空间不大,在暂时无法调整系统架构的情况下,只有使用.NET中的TPL解决一些模块耗时过多的问题.但在使用过程中也碰到了一些问题,现在把它写下来,用于备忘. 1. Paralle ...
- oracle使用parallel并行,多线程查询
insert into tmp (select /*parallel (a, 4)*/ * from plsuer.as_cdrindex_info_h partition(P_20170430) w ...
随机推荐
- TODO:Laravel 内置简单登录
TODO:Laravel 内置简单登录 1. 激活Laravel的Auth系统Laravel 利用 PHP 的新特性 trait 内置了非常完善好用的简单用户登录注册功能,适合一些不需要复杂用户权限管 ...
- 怎么让网站在本地支持SSL?
打开vs,点击项目,查看属性,打开ssl 如果有什么危险提示,就允许 右击项目,选择属性 运行项目
- 【Win 10 应用开发】启动远程设备上的应用
这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...
- Laravel 5.x 请求的生命周期(附源码)
Laravel最早接触是刚开始实习的时候,那时通过网上的学习资料很快便上手,开发模块接口.后来没有什么深入和总结,但是当我刚开始学Laravel的时候,我对Laravel最大的认识就是,框架除了路由. ...
- MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示(补充)
在2.1.栏目的前台显示中因右键没有添加视图把微软给鄙视了一下,后来有仔细研究了一下发现应该鄙视自己,其实这个功能是有的,是自己没搞清楚乱吐糟. 其实只要在NuGet中安装两个包(Microsoft. ...
- Android数据加密之SHA安全散列算法
前言: 对于SHA安全散列算法,以前没怎么使用过,仅仅是停留在听说过的阶段,今天在看图片缓存框架Glide源码时发现其缓存的Key采用的不是MD5加密算法,而是SHA-256加密算法,这才勾起了我的好 ...
- pt-pmp
pt-pmp有两方面的作用:一是获取进程的堆栈信息,二是对这些堆栈信息进行汇总. 进程的堆栈信息是利用gdb获取的,所以在获取的过程中,会对mysql服务端的性能有一定的影响. 用官方的话说: Thi ...
- 【踩坑速记】二次依赖?android studio编译运行各种踩坑解决方案,杜绝弯路,总有你想要的~
这篇博客,只是把自己在开发中经常遇到的打包编译问题以及解决方案给大家稍微分享一下,不求吸睛,但求有用. 1.大家都知道我们常常会遇到dex超出方法数的问题,所以很多人都会采用android.suppo ...
- MySQL 系列(四)主从复制、备份恢复方案生产环境实战
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- C#异步编程
什么是异步编程 什么是异步编程呢?举个简单的例子: using System.Net.Http; using System.Threading.Tasks; using static System.C ...