个人博客


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

用静态工厂方法替换构造函数

发表于 2019-04-10 | 分类于 effective java

这是根据effective java中的Item1条目来写的。在写java程序时,我们构造一个实例用的最多的就是调用类的构造函数.如A a = new A().但是还存在一种方法可以获取类的实例。而且相对于调用类的构造函数有很多好处,那就类的静态工厂函数。比如,在Java中的Boolean.valueOf(boolean b)方法:

1
2
3
public static Boolean valueOf(boolean b) {
return b ? Boolean.TRUE:Boolean.FALSE;
}

静态工厂函数相对于构造函数有优点也有缺点,下面会依次进行说明

优点

静态工厂函数相对于构造函数有具体的名字

首先,有具体的名字有什么好处呢?如果有名字,可以让调用者更加清楚此函数的作用。因为构造函数的名字要相同,那如果构造函数做的事情不一样,则只能通过增加或删除构造函数的入参才能表达不同的构造函数。这样子对于调用者会造成负担,调用者必须了解构造函数代码做的事情,才能知道此构造函数的真正目的。而使用静态工厂函数,可以通过合理取函数名称,来表达不同的目的以及区别。

静态工厂函数每次被调用时可以不需要创建新的对象

一般我们调用构造函数时,都是会返回一个新的对象。但是有时候我们不需要返回新的对象,比如单例模式。

静态工厂函数可以返回静态工厂函数返回类型的子类型

这个是什么意思呢?比如我们拿java中的Collections的静态工厂方法synchronizedMap为例:

1
2
3
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
return new SynchronizedMap<>(m);
}

可以看到函数定义的返回类型是Map,但是实际返回的类型是SynchronizedMap.但是这样做有什么好处呢?
这种方式可以隐藏实现类,从而形成一个非常紧凑的API。我们还是以Collections类为例。Collections框架中有45个接口实现工具实现,提供了不可修改集合、同步集合等。这些都是通过Collections提供静态工厂函数来实现,而且返回的子类型都是非公共的。所以Collections框架API比它导出45个独立的公共类要小的多,这样不仅减少了API的数量,同时也减少了框架使用者需要了解的概念。框架使用者不需要了解这45个实现类。同时因为返回的是接口类型,这也是很好的做法。

第四个优点,静态工厂函数返回的类可以根据输入参数来改变

静态工厂方法返回的类可以根据版本而改变。Java中的EnumSet类没有公共构造函数,只有静态工厂方法。

1
2
3
4
5
6
7
8
9
10
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
Enum<?>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");

if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}

通过代码我们可以看出,noneOf返回两个子类中的一个实例,这取决于底层enum类型的大小。如果有64个或更少的元素,那么返回一个long类型的RegularEnumSet实例;如果enum类型有65或更多的元素,方法将返回一个long[]类型的JumboEnumSet实例。
客户端感知不到这两个实现类的存在。如果 RegularEnumSet 不再为小型 enum 类型提供性能优势,它可能会在未来的版本中被消除,而不会产生不良影响。类似地,如果事实证明 EnumSet 有益于性能,未来的版本可以添加第三或第四个 EnumSet 实现。客户端既不知道也不关心从工厂返回的对象的类;它们只关心它是 EnumSet 的某个子类。

第五个优点,编写包含静态工厂函数的类时,此静态工厂函数返回对象所属的类可以不存在

上面这句话,听起来有点难以理解。这里做个例子进行说明,比如我们正在编写类A,其中包含factory1 静态工厂函数,factory1函数的定义返回类型是接口 Interface1,而实际

这一点暂时没有理解

缺点

第一个缺点,类如果没有公有或者受保护的构造器,那么此类就不能被继承。

例如,我们不能继承Collection框架中的任何类

第二个缺点,我们不太容易在类文档中找到静态工厂函数

因为Javadoc 工具不能明确的标注静态工厂函数,所以在文档中静态工厂函数就不会突出显示。而构造函数在文档中会突出显示。我们也可以遵守一些给静态工厂函数起名的规范,下面是一些建议:

  1. from: 将输入转为与之对应的相关类,接受一个参数,然后返回对应的类实例
    1
    Date d = Date.from(instant);
  2. of:接受多个参数,返回包含多个参数的类实例
    1
    Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  3. valueOf: 介于from和of之间
    1
    BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
  4. instance 或者getInstance:返回参数对应的类实例,但是值有可能会改变
    1
    StackWalker luke = StackWalker.getInstance(options);
  5. create 或者 newInstance: 类似于instance或getInstance,但是每次调用都会返回一个新的实例
    1
    Object newArray = Array.newIntance(classObject, arrayLen);
  6. getType: 类似getInstance,获取实例,但是静态工厂函数在另一个类中。Type表面返回实例的类型
    1
    FileStore fs = Files.getFileStore(path);
  7. newType: 类似newInstance,但是静态工厂函数在另一个类中
    1
    BufferedReader br = Files.newBufferedReader(path);
  8. type: 一种精确的转换
    1
    List<Complaint> litany = Collections.list(legacyLitany);

总结

构造器和静态工厂函数有各自的优点和缺点,但是一般来说,静态工厂函数要比构造器好。在平常的编程过程中,我们不要一上来就直接写构造函数,可以先考虑一下,用静态工厂函数是不是更好。

effective java third edition notes

发表于 2019-04-10

effective java third edition notes

记录阅读《effective java》得一些收获

第二章 创建和销毁对象

左耳朵耗子-陈皓经历(转)

发表于 2019-03-30 | 分类于 编程人生

左耳朵耗子-陈皓

一、个人简历

陈皓,coolshell.cn博客博主。
14年以上软件开发相关工作经验,8年以上项目和团队管理经验。
擅长底层技术架构,软件工程。
对高性能,高可用,分布式,高并发,大规模数据处理系统有一定研究。
技术擅长C/C++/Java和Unix/Linux/Windows。

二、轶事和思考

2.1、毅然辞掉银行工作

我当时在银行做银行网络、银行的电子邮件系统和办公自动化系统。当时正处在银行信息化的阶段,加上当时互联网和IT业刚刚火起来,得到这份工作其实是很幸运的。银行正值扩张电子信息化业务的时候,其实应该有很多事可做,但是当时的主要工作都是由厂商来干。比如说IBM或Cisco拿下单子来,会把工作外包给系统集成商。作为一位技术人员,其实可以发挥的空间并不大,多数时间我只是出了问题打电话的角色。没有人会教你任何事,出了问题,就是打电话,然后按照他们的指导来完成工作。但这个还不是促使我离职的最主要原因,我离开是因为互联网和IT业的兴起让我有些心向往之,有想去看一看的冲动。我还记得当时的辞职书是这么写的:“本人对现有工作毫无兴趣,申请辞职”。处长说,“你可以这么写,但是要加上‘经调解无效’,另外,分给你的房就不能要了”。我说好啊。就这样就辞去了工作,去了上海。老实说,这个决定真不好做,因为几乎所有的朋友和亲人都很反对。

2.2、选择上海闯荡的原因

当时选择上海是有原因的,我觉得在当时的环境(2000年)下,上海的发展比较不错。没有选择深圳的原因是个人感觉那是因为政治原因凭空冒出来的一座城市,我不是很喜欢。北京我有很多同学,而我想去一个陌生的地方。但是后来发现上海也不是做技术的地方,过得有些压抑,初来到上海的时候经常会被人瞧不起,毕竟是刚刚来到大城市。
我当时感觉银行束缚了我,想看看自己可以跑多远,能发挥出多大的价值。于是决定出来闯一闯,主要就是要去经历一些应该去经历的事情,不希望老了以后会后悔年轻的时候没有去。当时IT产业的发展是一个大趋势,我感觉我必须要去一座大城市,去经历一些东西。在小地方基本没有这些机会。要学会游泳就必须要跳到水里去呛两口水,所以我就义无反顾地出来了。

2.3、工作挫折和自省

我仍然记得自己拎着皮箱站在上海火车站的样子,举目无亲。原来在老家的时候觉得自己还挺厉害的,自以为不愁找不到好工作。不过事实却不是这样的。
我还记得第一次去面试时,(面试官)问了很多和C相关的问题,问了我半个小时,我一个问题都答不上来。我一直低着头,好像被审问的犯罪分子一样。我从大学毕业出来就没经历过什么面试,再加上自己内向的性格,所以,整个过程我都在低着头,不敢看别人一眼。最后,面试官问了我一个问题是“有不懂的问题你会怎么办”,这样的问题我都不敢回答,其实这道题的答案不过就是“问别人”或是“自己看书”或是“上网查资料”什么的。很显然,这场面试我肯定是被灭掉了。但这还没完,最后面试官对我说:“你出来干什么,像你这种性格根本不适合到大城市来”。
我当时被严重地打击了,感觉到自己确实有一些东西很差。第一个是性格差,不知道怎么与人交往;第二个是技术差,很多问题不知道;第三个就是视野狭窄,没见过世面。后面的几家公司的面试都大同小异。一个人在异地他乡,经历了这些事情,心里会非常地恐慌,“我这条路是不是走错了?”,我经常这样问自己。
面对这样的情况,我被逼迫着一定要改变自己。因为,离开银行时,我的家人、同学和朋友都很反对我出来,如果这样灰溜溜地回去,我面对不了他们。而前面的人还看不起我。我当时的处境真的很难堪,就像爬在悬崖中间,上不去也下不来。所以,当时只有一个想法,就是要证明自己不是那么差的人。人被逼到那个份上,活得就比较简单,哪有什么职业发展规划,只想拼命地多学技术,提高自己的能力。这个经历有点像是一剂兴奋剂,同时也相当阵痛。但是回头想想,第一个面试官应该是我最感谢的人。

2.4、疯狂成长

在同学的帮助下我找到了在上海的第一份工作。南天公司,这是一家给银行做系统集成软件的公司,大学毕业时本来也可以进去,现在绕了一圈而且还是靠同学帮助进去的,所以那时的心态还很不平稳;另一方面因为以前是做银行的,是甲方,现在成了乙方了,两边的人都用异样的眼光看我,心态非常不好。
不过,这是个技术不错的企业,国内早期很多搞Unix/C的高手都是从这个公司培养出来的。我当时的技术还是不行,比如说到了用户站点以后,不知道怎么做,我曾经误操作把用户的数据删掉了。经常犯低级错误,不但没做好自己的工作,反而还给别人添了麻烦。这些经历都让我有一种“技术焦虑感”,或者叫“技术忧郁症”。我觉得自己这也不行,那也不行。这也是我今天仍然在拼命学习的原因。这就好像我们经常在参加工作多年后还会梦见自己的英语四级没过,或者是期末考试没过一样。我经常会梦见的是项目又做砸了,又把用户的系统搞乱了,一大堆人要审我、要训斥我。
因为技术差,沟通差,不会面试,所以,我决定经常出去面试,基本上每周都要去,不管懂不懂,也不管是什么公司,也不管别人鄙不鄙视我,反正一有机会就去面试,多见见人这样可以让我的性格有所改善,同时,也可以知道社会上需要一些什么样的技能,把别人面我回答不上来的东西都记下来,然后回头找答案。那个时候我会经常去上海书城看书,看很多很多的书。我学的东西很杂,什么做网页,Windows,Unix,Java,.NET,flash,连3DMax/Photoshop我也学,还去考CCNA的认证等等。这样散乱地学习两年后,我才慢慢确定了要走C/C++/Unix/Windows系统底层的路子。而这样扑天盖地学习的结果有一个好处就是,我成长的速度相当之快。我自己摸索到了适合我的学习方法(从基础和原理上学习),从而不再害怕各种新的技术。那时,所有人都在休黄金周出去玩的时候,我还呆在办公室或住处看书学习。
等到一年半之后,用句赵本山的台词说,我在面试中学会抢答了。面试官的问题没问完,我就能说出答案了。其实,基本上是面一个公司过一个(当然都是一些小公司),此时,我就开始挑公司了。
感到技术能力不行就去学技术,交往能力不行我就去面试,这两个问题都可以通过大量地实践和努力来弥补,但是眼界这个东西没有办法通过努力来弥补。所以,当时非常想去一些更大的公司看看,如果能去外企更好。

2.5、变得不一样

我还记得,有一天,有一个和网络相关的技术问题,同事们搞了三四个通宵,也没弄明白,后来想起我好像在看这方面的书,他们就让我去看看、试试,结果我只用了20分钟就搞定了。基础真的很重要,这受益于我看了《TCP/IP详解》这套书。
后来,我去了一家做电信软件的公司,他们让我做PowerBuilder,尽管我当时想做的是C++,但是因为当时各种原因很需要这份工作,就去了。进了那里的第一天发现公司里有一个论坛,上面都是一些技术上悬而未决的问题,都是关于Windows/C++的。我一看,都是些很简单的问题,一下午的时间就被我全部解决掉了,我的基础知识发挥了作用。于是,当天下午我一下子就被调到了核心组。不过,我只在那里呆了两个多月,因为那时我已经不愁找工作了,这期间有两家北京的公司录用了我,于是,02年我就来到了北京,去到一家做分布式计算平台软件的公司。
在上海的这两年的时间,从什么都不是,到得到工作上的全面肯定。那段时间感觉自己牛得不得了,有些狂妄和骄傲了,经常上网和不认识的人争论一些很傻的问题,后来发展到对当时的领导以及银行客户的领导不敬,总觉得这些人太二。现在回头看过去,我觉得那是我人生特定时期的记号,人生的痕迹。

2.6、建立coolshell.cn的原因

我2002年在CSDN开了一个blog,当时叫专家专栏。开个专栏很简单,只要发6个帖子。我也不是什么专家,只是喜欢看书、喜欢学习而已,也喜欢做一些学习笔记。那时候没有笔记本也没有台式机,市面上好像也没有U盘和移动硬盘。正好有CSDN这么一个地方,就去CSDN的站点上把自己的一些学习笔记放在了上面。后来03年的时候技术专栏转到了博客,因为CSDN对其博客经营得不好,我09年就离开了csdn,创建了酷壳。花了4500块钱,租了一个server。我离开那里主要有两个原因,一个是因为当时CSDN博客有一些性能上的问题,.NET架构嘛,大家都懂的。另外一个原因就是当时出现了很多博客营销的站点,有点像今天的36氪。好像那时候出现最早的叫煎蛋,那上面会有一些报纸上不会出现的国外的趣闻,是以博客的方式形成的媒体。这和常规的以日记形式出现的博客大不一样。煎蛋、有意思吧等这些博客让我看到了博客还能这样写,我觉得很好玩儿。而我当时也经常会去国外社区看一些文章,也能看到一些有意思的东西(因为我当时有了学习瓶颈,国内的网站已经满足不了我了)。心想,既然这些东西这么有意思,我为什么不自己开一个博客呢?
我老婆是学新闻编辑的,她鄙视我说,你的博客虽然有很多人读,但是只能算是个书呆子的博客,全是一些书呆子式的文章。我有些不服,我觉得技术人员不全是书呆子,我们这个圈子里也有很多有趣的东西,只不过是你不知道而已。于是我想弄一个有意思的、有娱乐性质的东西,里面都是技术圈里面有意思的事儿,但是很多技术圈以外的人也能看懂。一开始酷壳和CSDN博客的风格完全迥然,如果有技术性的文章我还会在CSDN上贴,但是后来我就完全抛弃了原来CSDN上的博客。酷壳的初衷是希望很多人都可以来上面发表一些东西,但是可能是我写得太多了,别人就被压制住了。
现在博客更新频率是一周一篇,一开始的时候一周三篇。磨刀不误砍柴工,总是有时间来做这些事的。我经常看书,需要把学到的东西整理成学习笔记。自从在CSDN上写博客的时候,就有这样的习惯了,而且又有“技术焦虑症”,害怕跟不上,所以维护博客的事对我来说是很自然的。
现在我已经不用自己再租服务器了,由于酷壳的访问量比较有保证,我提供了广告位,就免费得到服务器了。

2.7、对于新技术的态度

遇到新技术我会去了解,但不会把很大的精力放在这。这些技术尚不成熟,我只需要跟得住就可以了。我的团队自己想学什么我都不干涉,但是用到项目里的技术,必须是很成熟的,(技术应用)十年以上可能是一个门槛。有人说技术更新换代很快,我一点儿都不这样想。虽然有不成熟的技术不断地涌出,但是成熟的技术,比如Unix,40多年,C,40多年,C++,30多年,Java也有将近20年了……,所以,技术并不多啊。还有很多技术比如Ruby,Lisp这样的,它们没有进入主流的原因主要是缺少企业级的应用背景。
如果要捋一个脉络下来,70年代Unix的出现,是软件发展方面的一个里程碑,那个时期的C语言,也是语言方面的里程碑。当时所有的项目都在Unix/C上,全世界人都在用这两样东西写软件。Linux跟随的是Unix,Windows下的开发也是C。这时候出现的C++很自然就被大家接受了,企业级的系统很自然就会迁移到这上面,C++虽然接过了C的接力棒,但是它的问题是它没有一个企业方面的架构,否则也不会有今天的Java。C++和C非常接近,它只不过是C的一个扩展,长年没有一个企业架构的框架。而Java出现之后,IBM把企业架构这部分的需求接了过来,J2EE的出现让C/C++捉襟见肘了,后面还有了.NET,但可惜的是这只局限在Windows平台上。这些就是企业级软件方面语言层面这条线上的技术主干。

另外一条脉络就是互联网方面的(HTML/CSS/JS/LAMP…)。这条脉络和上述的那条C/C++/Java的我都没有放,作为一个有技术忧虑症的人,这两条软件开发的主线一定不能放弃。无论是应用还是学术,我都会看,知识不愁多。何必搞应用的和搞学术的分开阵营,互相看不起呢?都是知识,学就好了。
技术的发展要根植于历史,而不是未来。不要和我描述这个技术的未来会多么美好,用这个技术可以实现什么花哨的东西。很多常青的技术都是承前的。所以说“某某(技术)要火”这样的话是没有意义的,等它火了、应用多了咱们再说嘛。有些人说不学C/C++也是没有问题的,我对此的回应是:如果连主干都可以不学的话,还有什么其他的好学呢?极端一点,我要这么说:这些是计算机发展的根、脉络、祖师爷,这样的东西怎么可以不学呢?大部分学校虽然都会教授C,但是教得都不好。学校喜欢教微软的东西,老师好教学生好学。我不是说Windows不好,但那不是计算机文化的主干,那只是微软的主干、PC的主干。整个计算机文化的主干肯定是源起于Unix/C这条线上(注意,我说的是文化不是技术)。我也写过很多与Unix文化相关的文章,大家可以看看我写的“Unix传奇”。

2.8、对于学校计算机科学教育的看法

学校教的大部分都是知识密集型的技术,但是社会上的企业大部分都是劳动密集型的。什么是劳动密集型的企业呢?麦当劳炸薯条就是劳动密集型的工作,用不到学校教授的那些知识。如果有一天你不炸薯条了,而要去做更大更专业的东西,学校里的知识就会派上用场。有人说一个语言、一个技术,能解决问题能用就行了,我不这样认为。我觉得你应该至少要知道这些演变和进化的过程。而如果你要解决一些业务和技术难题,就需要抓住某种技术很深入地学习,当成艺术一样来学习。

我在“软件开发‘三重门’”里说过,第一重门是业务功能,在这重门里,的确是会编程就可以了;第二重门是业务性能,在这一重门里,技术的基础就很管用了,比如:操作系统的文件管理,进程调度,内存管理,网络的七层模型,TCP/UDP的协议,语言用法、编译和类库的实现,数据结构,算法等等就非常关键了;第三重门是业务智能,在这一重门里,你会发现很多东西都很学院派了,比如,搜索算法,推荐算法,预测,统计,机器学习,图像识别,分布式架构和算法等等,你需要读很多计算机学院派的论文。
总之,这主要看你职业生涯的背景了,如果你整天被当作劳动力来使用,你用到的技术就比较浅,比较实用,但是如果你做一些知识密集型的工作,你就需要用心来搞搞研究,就会发现你需要理论上的知识。比如说,我之前做过的跨国库存调配,需要知道最短路径的算法,而我现在在亚马逊做的库存预测系统,数据挖掘的那些东西都需要很强的数学建模、算法、数据挖掘的功底。
我觉得真正的高手都来自知识密集型的学院派。他们更强的是,可以把那些理论的基础知识应用到现在的业务上来。但很可惜,我们国内今天的教育并没有很好地把那些学院派的理论知识和现实的业务问题很好地结合起来。比如说一些哈希表或二叉树的数据结构,如果我们的学校在讲述这些知识的时候能够结合实际的业务问题,效果会非常不错,比如:设计一个IP地址和地理位置的查询系统,设计一个分布式的NoSQL的数据库,或是设计一个地理位置的检索应用等等。在学习操作系统的时候,如果老师可以带学生做一个手机或嵌入式操作系统,或是研究一下Unix System V或是Linux的源码的话,会更有意思。在学习网络知识的时候,能带学生重点学一下以太网和TCP/IP的特性,并调优,或是能做一个网络上的Pub/Sub消息系统或是做一个像Nginx一样的web server,那会更好。如果在学图形学的过程中能带领学生实践开发一个作图工具或是一个游戏引擎,那会更有意思。
总之,我们的教育和现实脱节太严重了,教的东西无论是在技术还是在实践上都严重落后和脱节,没有通过实际的业务或技术问题来教学生那些理论知识,这是一个失败。

2.9、如何在压力下,享受技术带来的快乐

中国人中庸的思想,入世和出世,每天的工作就是入世。举个例子,在上海的时候,给交通银行做项目的时候,每周休息一天,早九点到晚十点,每天工作12个小时,这样的工作持续了一整年,没有节假日,项目上的技术也没什么意思。当时我晚上十点回到住处,还想学一些C++/Java和Unix/Windows的技术,于是就看书到晚上11:30,每天如此,一年下来学到很多东西,时间没有荒废,心里就很开心。我觉得当时是快乐的,因为有成长的感觉是快乐的。

现在的我,工作、写博客、养孩子,事情其实更多。我早上7:30起床,会浏览一下国外的新闻,hacker news,tech church,reddit,highavailability之类的站点,9点上班。晚上6、7点钟下班,开始带孩子。十点钟孩子睡了觉,我会开始重新细读一下这一天都发生了些什么事情。这个时间也有可能会用来看书。学习的过程我是不喜欢被打断的,所以从十点到十二点,家人都睡了,这正是我连续学习的好时间。可能从晚上11:30开始,我会做点笔记或者写博客。我现在对酷壳文章的质量要求比较高一些,所以大概积累一个星期的时间才可以生成一篇文章。每天我大概都在一两点钟才会睡觉。没办法,我有技术焦虑症。但是觉得这样的生活很充实,也很踏实。
另外,任何一门技术玩深了,都是很有意思的。有些人形成了一个价值取向,“我只做什么,绝不做什么”。前段时间有一个刚来亚马逊的工程师,他原来做的是数据挖掘推荐系统,后来公司重组要他做前端,他不肯。我觉得,前端后端都是编程,Javascript是编程,C++也是编程。编程不在于你用什么语言去coding,而是你组织程序、设计软件的能力,只要你上升到脑力劳动上来,用什么都一样,技术无贵贱就是这个意思。
回到问题,怎么才能享受到快乐呢?第一,入世和出世要分开,不要让世俗的东西打扰到你的内心世界,你的情绪不应该为别人所控,也不应该被世俗所污染,活得真实,你才会快乐。第二点就是要有热情,有了热情,你的心情就会很好,加班都可以是快乐的,想一想我们整个通宵用来打游戏的时光,虽然很累,但是你也很开心,这都是因为有了热情的缘故。

2.10、做自己是最难的

我承认我活在我的精神家园里面。我推荐大家看一下王小波的《我的精神家园》,这篇文章对我的影响非常大。看了这篇文章,你就会明白我为什么要躺在自己的池子里,如果不想被这个社会所污染,就必须要躺在自己的池子里。做大众是很容易的,做自己是最难的。当你老了的时候,回想过去,如果你是为自己而活的,你总会觉得很踏实。可能有人会觉得我偏激,没关系,为什么要所有人看法都一致呢?世界因为不同而美丽,多元化的价值观并不冲突。

转载自:http://www.ituring.com.cn/article/9174

pip以及conda镜像源修改及命令使用

发表于 2019-03-25 | 分类于 python

Python包的安装

在国内环境下,因为网络原因,所以Python下很多包安装不了或者安装的速度很慢。这里主要介绍下如何修改conda以及pip对应的镜像源。

pip

pip主要是用来管理python包的工具,类似于Maven工具。

临时修改pip安装源

比如我们要安装gevent包,我们可以输入一下命令

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple gevent

这样就会从清华这边的镜像去安装gevent库.其中-i参数指定了使用清华的pip源

有时候可能需要添加受信源,命令如下:

1
pip install packagename -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

其中--trusted-host 参数是指设置为受信源,否则在安全性较高的连接下是连接不上的

永久修改

在用户根目录(~,而非系统根目录 / )下添加配置~/.pip/pip.conf目录添加可信源,如果目录文件不存在,可直接创建。写入如下内容:

1
2
3
[global]
index-url=http://pypi.douban.com/simple
trusted-host = pypi.douban.com

这里添加的是豆瓣源,也可以添加清华源

conda使用及源修改

conda是Anaconda中用来安装python包的工具。在Anaconda中将镜像分为两类,一类是官方的python包,放在anaconda中;另一类是第三方的python包,放在conda-forge中。

采用conda 安装python包时,可以使用以下命令:

1
conda install -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/linux-64 joblib

其中参数-c指定了镜像源的通道,这里实在anaconda官方中安装joblib

或者

1
conda install -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64 jieba

这里是在conda-forge中安装jieba第三方的Python包

BIO NIO AIO详解

发表于 2019-03-23 | 分类于 java

Java BIO NIO AIO详解

同步,异步,阻塞,非阻塞

这几个概念理解起来确实比较困难,特别是同步和阻塞,异步和非阻塞。首先要明确的一个概念是同步和异步主要是关注的是消息通信机制,所以同步和异步主要是关注客户端和服务端两个方面的消息如何通信。而阻塞和非阻塞主要是等待调用结果时的状态,所以关注的主要是当前线程在等待结果时能够做什么,如果在等待结果时当前线程能够做其他的事,则线程是非阻塞的;如果只能等待返回结果,则当前线程是阻塞的。下面举个例子来具体说明一下:
比如你跟书店老板打电话,确认是否书店中有哈利波特这本书。书店老板电话没有挂断,说你等一下,我现在查一下,你一直在等待,此时就是一种同步通信。而如果老板说我晚点电话通知你,然后挂断电话,此时就是异步通信。
让我们在换一个视角,还是打电话确定是否有哈利波特这本书这件事情。在打电话的过程中,你什么都没有干,只是一直在等待,那么此时你就是处于阻塞状态。而如果此时你正在看电视,此时你就是非阻塞状态,但是需要不定时的检查一下电话那边有没有回复。

所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果.
而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
在IO操作中,有以下四种组合:

  1. 同步阻塞IO:调用者发起IO操作请求,等待IO操作完成(阻塞)。IO操作的过程需要等待,等待服务端返回结果,操作执行完成后返回结果(同步)
  2. 同步非阻塞:调用者发起IO操作请求,询问IO操作的的状态,如果未完成,则立即返回;如果完成,则返回结果(非阻塞)。IO操作的过程需要等待执行完成才返回结果(同步)
  3. 异步阻塞:调用者发起IO操作请求,等待IO操作完成在返回(阻塞)。IO操作的过程不需要等待,操作完成后通过通知或者回调获取结果(异步)
  4. 异步非阻塞:调用者发起IO操作请求,询问IO操作的状态,如果未完成,则立即返回;如果完成,则返回结果(非阻塞)。IO操作的过程不需要等待,操作完成后通过通知或回调获得结果(异步)
    在下面的具体介绍中,我会进行具体的说明。

Java IO 操作类

Java中进行IO操作的类一般分为以下四类:

  1. 字节流的输入和输出:InputStream和OutputStream
  2. 字符流的输入和输出
  3. 网络编程Socket

BIO

首先BIO是同步阻塞调用。阻塞是因为服务端在调用accept方法时,服务端会一直阻塞在accept方法上,直到在对应的端口上接收到数据;同步是因为客户端会一直等待服务端执行完成才返回结果。可以想一下JavaScript中的Ajax请求,在异步Ajax请求发出后,浏览器会执行接下来的JS代码,直到服务端发回处理结果,然后执行对应的回调函数。这是典型的异步请求。

NIO

NIO(New IO or Non-Block IO)是一种同步非阻塞的通信模式。NIO客户端和服务器之间通过Channel通信。NIO可以在Channel进行读写操作。这些Channel都会被注册在Selector多路复用器上。Selector通过一个线程不停的轮询这些Channel。找出已经准备就绪的Channel执行IO操作。说是非阻塞是因为NIO通过一个线程轮询,实现千万个客户端的请求。说是同步是因为客户端一直在等待服务端执行完成才返回结果。

AIO

总结

参考链接

2019-plan-and-learn

发表于 2019-01-05 | 分类于 plan

2019计划

激励左耳朵耗子

目标

  1. 掌握tensorflow的使用
  2. 掌握Python以及常用库(numpy,matplotlib,pandas)的使用
  3. 掌握常用机器学习算法(SVM,AdaBoost,LightGBM)的使用以及理论
  4. 掌握深度学习常用算法应用和理论
  5. 掌握英语单词5000个,提高自己的英语发音
  6. spark大数据分析技术
  7. linux相关技术
  8. Java相关技术

具体实现

今天看了一篇虎扑上面<非CS专业转行机器学习/人工智能阶段性成功,分享一点个人经验吧>的帖子,感触比较多,摘一点帖子里面的内容,为之后的学习提供一定的建议。
楼主的情况是没有人工智能基础的,为了找到人工智能的工作准备了两年时间。

编程:掌握一门语言,要达到非常熟悉的阶段。
数据结构:掌握常用的数据结构,多做leetcode上面的编程题目,至少要刷一下easy和medium模式的题目,写的时候考虑test case
机器学习:

1. andrew ng的machine learning,仔细看课件和习题
2. hands on machine learning with scikit-learn and tensorflow,并且在pythhon中实践还有课后习题
3. bishop的pattern recognition and machine learning
4. 李彦宏的机器学习和深度学习(自己加的)
5. 李航的统计机器学习(自己加的)

Java相关技术

参考了v2ex 或者github
这里做了一个思维导图

下面进行思维导图的一些解释。同时对这些技能点进行查漏补缺,同时也会在之后的过程中添加更多的技能点

集合

集合主要是java.util包下的非线程安全和线程安全集合

非线程安全

  1. List: ArrayList与LinkedList的实现和区别
  2. Map:
    • HashMap:了解其数据结构,源码,hash冲突如何解决(链表和红黑树),扩容时机,扩容时避免rehash优化
    • LinkedHashMap:了解基本原理,哪两种有序,如何实现LRU
    • TreeMap:了解数据结构,了解其key对象为什么必须要实现Compare接口,如何用它实现一致性哈希
  3. Set:基本上是由map实现,简单看看就好

常见问题

  • hashmap 如何解决 hash 冲突,为什么 hashmap 中的链表需要转成红黑树?
  • hashmap 什么时候会触发扩容?
  • jdk1.8 之前并发操作 hashmap 时为什么会有死循环的问题?
  • hashmap 扩容时每个 entry 需要再计算一次 hash 吗?
  • hashmap 的数组长度为什么要保证是 2 的幂?
  • 如何用 LinkedHashMap 实现 LRU ?
  • 如何用 TreeMap 实现一致性 hash ?

线程安全的集合

  1. Collection.synchronized:了解其实现原理
  2. CopyOnWriteArrayList:了解写时复制机制,了解其适用场景,思考为什么没有ConcurrentArrayList
  3. ConcurrentHashMap:了解实现原理,扩容时做的优化,与HashTable的对比
  4. BlockingQueue:了解 LinkedBlockingQueue、ArrayBlockingQueue、DelayQueue、SynchronousQueue

常见问题

  • ConcurrentHashMap 是如何在保证并发安全的同时提高性能?
  • ConcurrentHashMap 是如何让多线程同时参与扩容?
  • LinkedBlockingQueue、DelayQueue 是如何实现的?
  • CopyOnWriteArrayList 是如何保证线程安全的?

并发

  1. synchronized:了解偏向锁、轻量级锁、重量级锁的概念以及升级机制、以及和 ReentrantLock 的区别
  2. CAS:了解 AtomicInteger 实现原理、CAS 适用场景、如何实现乐观锁
  3. AQS:了解 AQS 内部实现、及依靠 AQS 的同步类比如 ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier 等的实现
  4. ThreadLocal:了解 ThreadLocal 使用场景和内部实现
  5. ThreadPoolExecutor:了解线程池的工作原理以及几个重要参数的设置

常见问题

  • synchronized 与 ReentrantLock 的区别?
  • 乐观锁和悲观锁的区别?
  • 如何实现一个乐观锁?
  • AQS 是如何唤醒下一个线程的?
  • ReentrantLock 如何实现公平和非公平锁是如何实现?
  • CountDownLatch 和 CyclicBarrier 的区别?各自适用于什么场景?
  • 适用 ThreadLocal 时要注意什么?比如说内存泄漏?
  • 说一说往线程池里提交一个任务会发生什么?
  • 线程池的几个参数如何设置?
  • 线程池的非核心线程什么时候会被释放?
  • 如何排查死锁?

引用

了解 Java 中的软引用、弱引用、虚引用的适用场景以及释放机制

常见问题

  • 软引用什么时候会被释放
  • 弱引用什么时候会被释放

类加载

了解双亲委派机制

常见问题

  • 双亲委派机制的作用?
  • Tomcat 的 classloader 结构
  • 如何自己实现一个 classloader 打破双亲委派

IO

了解 BIO 和 NIO 的区别、了解多路复用机制

常见问题

  • 同步阻塞、同步非阻塞、异步的区别?
  • select、poll、eopll 的区别?
  • java NIO 与 BIO 的区别?
  • refactor 线程模型是什么?

JVM

了解GC和内存区域

  1. 垃圾回收基本原理、几种常见的垃圾回收器的特性、重点了解 CMS (或 G1 )以及一些重要的参数
  2. 能说清 jvm 的内存划分

常见问题

  • CMS GC 回收分为哪几个阶段?分别做了什么事情?
  • CMS 有哪些重要参数?
  • Concurrent Model Failure 和 ParNew promotion failed 什么情况下会发生?
  • CMS 的优缺点?
  • 有做过哪些 GC 调优?
  • 为什么要划分成年轻代和老年代?
  • 年轻代为什么被划分成 eden、survivor 区域?
  • 年轻代为什么采用的是复制算法?
  • 老年代为什么采用的是标记清除、标记整理算法
  • 什么情况下使用堆外内存?要注意些什么?
  • 堆外内存如何被回收?
  • jvm 内存区域划分是怎样的?

Spring

bean 的生命周期、循环依赖问题、spring cloud (如项目中有用过)、AOP 的实现、spring 事务传播

常见问题

  • java 动态代理和 cglib 动态代理的区别(经常结合 spring 一起问所以就放这里了)
  • spring 中 bean 的生命周期是怎样的?
  • 属性注入和构造器注入哪种会有循环依赖的问题?

Mysql

事务隔离级别、锁、索引的数据结构、聚簇索引和非聚簇索引、最左匹配原则、查询优化( explain 等命令)

常见问题

  • Mysql(innondb 下同) 有哪几种事务隔离级别?
  • 不同事务隔离级别分别会加哪些锁?
  • mysql 的行锁、表锁、间隙锁、意向锁分别是做什么的?
  • 说说什么是最左匹配?
  • 如何优化慢查询?
  • mysql 索引为什么用的是 b+ tree 而不是 b tree、红黑树
  • 分库分表如何选择分表键
  • 分库分表的情况下,查询时一般是如何做排序的?

算法

准备一下leetcode上的算法(easy,medium)

tensorboard介绍

发表于 2018-12-26 | 分类于 tensorflow

最近因为工作需要,看了下tensorboard的使用方式,这里做了简单的学习记录。使用的tensorflow版本是1.10.0,tensorboard的版本也是一样。

tensorboard介绍

tensorboard主要是为了查看tensorflow程序,将程序进行图示化,可以用来查看程序的运行情况,也可以用来debug程序。

tensorflow写tensorboard日志

在程序中主要使用tf.summary.FileWriter来将需要记录的事件日志记录到硬盘中。这个函数主要由三个参数需要注意的,如果想要查看详细的内容,可以去源码中查找具体的使用方式。

1
2
3
logdir:指定日志写入的具体目录
graph:指定记录的tensorflow图
filename_suffix:事件日志文件的后缀

tensorboard启动

tensorboard的启动是在命令行中,输入tensorboard --logdir=/path/to/log命令启动,然后打开ip+port在浏览器中进行查看。查看tensorboard的参数信息,可以运行tensorboard --help来进行查看。

1
2
--inspect: 用来查看事件日志信息,并不启动tensorboard
--logdir:用来指定事件日志的存储目录

tensorboard主要是扫描logdir指定目录下的内容,扫描文件名带有.tfevents.的文件进行展示。如果logdir下有多个目录,则在浏览器中可以分别进行浏览。如果有多个相同的文件,则会显示时间戳距离最近的文件。文件名中带有时间戳。例如:events.out.tfevents.1545795299.DESKTOP-123

欧洲四国行

发表于 2018-12-22 | 分类于 欧洲 , 旅行

今年九月份去了一趟欧洲,总共去了有十五天的样子。去了比利时,西班牙(巴萨罗那),葡萄牙(里斯本),法国(巴黎)四个国家。除了比利时,其他的三个国家都是只去了一个城市。

比利时

比利时是我到达欧洲的第一站,第一天主要是在布鲁塞尔市内玩。去了市中心的大广场,雨果笔下世界上最美丽的广场。第一眼看到此广场,给我很大的震撼,整个广场四周全部是欧式建筑,有巴洛克式,也有哥特式。建筑上面的人物雕塑也非常精美。置身其中,你能感觉到建筑帮助我直达它所在的那个年代,像我展示着那个时代的辉煌。而且这种建筑不单单只是作为居住或者商业的功能,它的美感也是其重要的组成部分。第二天去了比利时的古城-布鲁日,还有靠近海边的城市奥斯坦德。早上早早出发,乘坐火车前往布鲁日,到了地方,渐渐的天空中开始飘起雨。可能因为前一天看了布鲁塞尔的大广场,来到布鲁日,虽然建筑很好看,但是并没有给我很大的震撼了。现在回想起来,也就能记得当时主要是沿布鲁日古城区转了转,并没有特别深的印象了。因为准备工作做得不足,本来想要去奥斯坦德看下北海的,但是到了地方之后,发现太冷了,也就没有转,下了火车就又回去了,也是一个遗憾吧。
来比利时之前,并不是怎么了解这个国家。来了之后发现国家虽然小,但是有名的东西还是很多的。首先是啤酒。可能说到啤酒,大家想到的一个就是德国。但是来了比利时之后,才发现比利时啤酒才真的是啤酒的王国。首先不像德国啤酒种类较为较为单一,这里的啤酒种类非常丰富,据说有四五百种。而且大街上酒吧也非常密集。假如超市里面只有六个货架,那么光酒就能占三个货架,哈哈。来到此地,怎么能不尝尝呢?去超市买了七八种啤酒,还有一瓶产自法国勃艮第的红酒。三天时间全部被我喝完了,这里的啤酒真的名不虚传,味道真不错,比国内的啤酒强太多了。哎,现在想喝也很难喝到了。说到啤酒,为啥比利时这么多呢?据说因为比利时地势较为低,水不好喝,比较涩口,所以采用本地的水和啤酒花酿做了啤酒。原来比利时人是将啤酒作为水的替代品了。虽然啤酒种类很多,但是这里有一种啤酒很难喝到。它就是修道院啤酒。虽然价格不是很贵,但是真的很难买到,而且被评价为最好喝的啤酒。首先,全球能够生产修道院啤酒只有七个修道院,荷兰有一家,比利时占了剩下六家,三家在比利时的荷语区,三家在比利时的法语区。并且每年生产的啤酒就那么多,不会有多的。这些啤酒都是修道院里面的修士酿造的。修士除了平时进行宗教的学习,剩下很多的时间都在潜心专研如何酿造好喝的啤酒。比利时除了啤酒以外,还有它的巧克力也是全球闻名。路边的巧克力店很多。还有炸薯条。

巴塞罗那

里斯本

巴黎

docker安装sshd以及修改镜像源和软件源

发表于 2018-12-20 | 分类于 docker

总览

因为最近公司需要在容器中跑深度学习任务,所以需要tensorflow的镜像。并且要求在要通过ssh进行容器的通信。这篇文章主要介绍如何在docker容器中安装软件,如何修改docker镜像源以及修改容器内部软件源地址。
宿主机环境:

1
2
3
uname -r : 3.10.0-862.11.6.el7.x86_64
cat /etc/redhat-release : CentOS Linux release 7.5.1804 (Core)
docker version : 18.06.0-ce

镜像主要选择的是官方的tensorflow:1.12.0-py3版本,镜像里面使用的系统环境下面会介绍

修改docker镜像源

!参考
由于docker 官方的镜像源在国外,导致下载速度很慢。所以第一步是修改docker镜像源地址。我这里采用永久修改docker镜像源地址。打开/etc/docker/daemon.json(如果没有此文件,则新建),添加如下内容:

1
2
3
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}

然后运行docker pull registry.docker-cn.com/tensorflow/tensorflow:1.12.0-py3
即可以拉取镜像,而且可以看到速度提升很快

启动镜像

我们可以使用docker images查看本机有的镜像。针对上面拉取的tensorflow:1.12.0-py3镜像,我们执行下面命令启动

1
docker run -it [image_name] /bin/bash

此时我们应该是在启动的容器中。我们可以查看容器具体的系统信息。因为tensorflow基础镜像是ubuntu,所以这里运行以下命令,因为容器中一般不会有vim命令,所以采用cat命令参看系统信息。注意下面的命令都是在容器中键入

1
2
uname -r
cat /etc/issue

查看得到系统信息为:Ubuntu 16.04.5 LTS

修改容器中软件源地址

由于容器中软件源默认地址是国外的,这里换成国内的。

1
2
cd /etc/apt
cp sources.list sources.list.bak

这里使用阿里的镜像源,将sources.list里面的内容修改为如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial main main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse

# 预发布软件源,不建议启用
# deb http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse
# deb-src http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse

容器中安装软件

1
2
3
4
passwd
apt-get update
apt-get install vim
apt-get install openssh-sshd

修改root密码以及安装完上面vim和openssh-sshd两个软件后,修改openssh-sshd配置文件内容。打开/etc/ssh/sshd_config将PermitRootLogin后面添加yes,即允许以root用户登录。后面启动sshd命令可能会报错,具体问题可以自己上网上搜索

生成镜像

退出镜像,将容器提交为镜像

1
docker commit [containerID] [image_name]

执行docker images可以看到生成的镜像。启动此镜像并开启sshd服务命令如下

1
2
docker run -d  -p 50001:22 [images_name] /usr/sbin/sshd -D
其中 -d表示已后台方式启动容器,-p挂载端口 ,/usr/sbin/sshd -D 是启动命令

集成算法

发表于 2018-12-01
<1234>

37 日志
22 分类
45 标签
RSS
© 2024 liang
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4