小象编程冰雪世界千鸟之国中的第7关攻略

小象编程第五关怎么过关_百度知道
小象编程第五关怎么过关
小象编程第五关怎么过关
我有更好的答案
ts violent content, remained avai
为您推荐:
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。小象编程第五关怎么过_百度知道
小象编程第五关怎么过
我有更好的答案
可能是你做的太小了,无论形状再像,长度和宽度不达到标准就没星
哪个场景里的第五关?
那个是森林的第五关吗?
为您推荐:
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。社会化媒体
了解更多>>
桂ICP备 号
阅读下一篇
自媒体运营攻略
行业经验交流
Hi,在你登录以后,就可以永久免费的收藏任何您感兴趣的内容,关注感兴趣的作者!
手机注册或邮箱注册
点击按钮进行验证
请输入正确的邮箱
已有帐号请点击
帐号创建成功!
我们刚刚给你发送了一封验证邮件
请在48小时内查收邮件,并按照提示验证邮箱
感谢你对微口网的信任与支持
你输入的邮箱还未注册
还没有帐号请点击
点击按钮进行验证
你输入的邮箱还未注册
又想起来了?
你已成功重置密码,请妥善保管,以后使用新密码登录
邮件发送成功!
我们刚刚给你发送了一封邮件
请在5分钟内查收邮件,并按照提示重置密码
感谢你对微口网的信任与支持
对不起,你的帐号尚未验证
如果你没有收到邮件,请留意垃圾箱 或
意见与建议
请留下您的联系方式
* 留下您正确的联系方式,以便工作人员尽快与你取得联系
转藏至我的藏点&p&我用 C 语言基于 SDF 建模画了一朵玫瑰,可以插入名字的字母(下图隐藏了milo)。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-be96dedecb881_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1286& data-rawheight=&1290& class=&origin_image zh-lightbox-thumb& width=&1286& data-original=&https://pic2.zhimg.com/v2-be96dedecb881_r.jpg&&&/figure&&p&另一个角度的着色变化较多一些:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-e39cbf0f0aeb2e0d4dac6d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1276& data-rawheight=&1284& class=&origin_image zh-lightbox-thumb& width=&1276& data-original=&https://pic2.zhimg.com/v2-e39cbf0f0aeb2e0d4dac6d_r.jpg&&&/figure&&hr&&h2& 6:30 更新:源文件&/h2&&p&我原来是在 &a href=&//link.zhihu.com/?target=https%3A//www.shadertoy.com/view/XsdyWr& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ShaderToy: Milo's Rose&/a& 建模及测试的。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-fb27b818bc3adb_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1720& data-rawheight=&1524& class=&origin_image zh-lightbox-thumb& width=&1720& data-original=&https://pic4.zhimg.com/v2-fb27b818bc3adb_r.jpg&&&/figure&&p&C 语言版本的源文件在 &a href=&//link.zhihu.com/?target=https%3A//github.com/miloyip/misc/blob/master/rose/rose.c& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&rose.c&/a& 。&/p&&p&一些注意的地方如下:&/p&&ul&&li&生成的文本是 160x80 个字符,如命令行不能显示这么多字符,可重定向到文件(如 &img src=&//www.zhihu.com/equation?tex=%5Ctexttt%7Brose+%3E+rose.txt%7D& alt=&\texttt{rose & rose.txt}& eeimg=&1&& ),用编辑器打开。&/li&&li&要加入名字等字符,修改 146 行,如插入 &milo&(这里接入&olim& 会好看一些),并把最后的 12.0f 改成 16.0f:&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&n&&putchar&/span&&span class=&p&&(&/span&&span class=&s&&&
.,-:;+=olim*#@@&&/span&&span class=&p&&[(&/span&&span class=&kt&&int&/span&&span class=&p&&)(&/span&&span class=&n&&f&/span&&span class=&p&&(&/span&&span class=&n&&make2&/span&&span class=&p&&((&/span&&span class=&n&&x&/span& &span class=&o&&/&/span& &span class=&mf&&160.0f&/span& &span class=&o&&-&/span& &span class=&mf&&0.5f&/span&&span class=&p&&)&/span& &span class=&o&&*&/span& &span class=&mf&&2.0f&/span&&span class=&p&&,&/span& &span class=&p&&(&/span&&span class=&n&&y&/span& &span class=&o&&/&/span& &span class=&mf&&80.0f&/span& &span class=&o&&-&/span& &span class=&mf&&0.5f&/span&&span class=&p&&)&/span& &span class=&o&&*&/span& &span class=&o&&-&/span&&span class=&mf&&2.0f&/span&&span class=&p&&))&/span& &span class=&o&&*&/span& &span class=&mf&&16.0f&/span&&span class=&p&&)]);&/span&
&/code&&/pre&&/div&&ul&&li&第 143 行用&a href=&//link.zhihu.com/?target=https%3A//zh.wikipedia.org/wiki/ANSI%25E8%25BD%25AC%25E4%25B9%%25BA%258F%25E5%& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ANSI转义序列&/a& 改变文本颜色,需要终端支持。可按需修改颜色。&/li&&li&第 128、129 行是摄影机的位置和方向,建议修改。可在 ShaderToy 里试好才改 C 文件。&/li&&/ul&&hr&&h2&相关答案和文章&/h2&&ul&&li&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&如何用 C 语言画「心形」? - 知乎&/a&&/li&&li&&a href=&https://www.zhihu.com/question//answer/& class=&internal&&如何用 C 语言画一个“圣诞树”?&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&如何用 C 语言画这个图 - 知乎专栏&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&用 C 语言画科赫雪花 - 知乎专栏&/a&&/li&&/ul&
我用 C 语言基于 SDF 建模画了一朵玫瑰,可以插入名字的字母(下图隐藏了milo)。另一个角度的着色变化较多一些: 6:30 更新:源文件我原来是在
建模及测试的。C 语言版本的源文件在
。一些注意的地方如下:生成的…
&figure&&img src=&https://pic3.zhimg.com/v2-3bcd33870a3eea0d0b024_b.jpg& data-rawwidth=&1000& data-rawheight=&1376& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&https://pic3.zhimg.com/v2-3bcd33870a3eea0d0b024_r.jpg&&&/figure&&p&////在讲zk的选主前,先普及几个概念,即分布式的逻辑时钟,paxos算法的简单普及&/p&&p&
分布式系统中,由于是分布在不同的机器上,完全无法使用物理上的时钟来表示,仅能依赖于网络的通讯,而由于通讯之间存在某种因果关系。在分布式系统中的事件存在潜在地因果关系,一个事件C是另外一个事件E的因,或者称C发生在e之前(&i&c &/i&happened before &i&e)&/i&,具体情况可能是: 当且仅当两个事件都在同一个节点服务器生,C首先执行,或者两个事件在不同节点上发生,e通过接受消息也知道了c发生。如果事件之间彼此不认识,那么称它们为同时发生。那么就可以认为c——&e,那么就可以依靠这些因果关系建立一些形如(1,0,1)的向量时钟等。&/p&&p&
大家看到网上很多的文章基本都是在说paxos怎么难理解,说什么是分布式系统唯一可靠的算法,但是看着那个拜占庭问题很难下手实现。其实还是由于不过理解以及作者阐述时没有个特定告诉我们怎么实现或者怎么证明说这个算法是正确的。paxos描述的是一个依赖于多数即可运行高可用、高一致的实现,那么为什么是正确的呢?这是需要保留的一个疑问,我们可以通过收敛的方法来看它为什么可以保证一致。这里不再多说,直接上个引用&a href=&https://www.zhihu.com/question//answer/& class=&internal&&如何浅显易懂地解说 Paxos 的算法?&/a&大神论证得很不错,我概述下,目的为了保证只能接受一个,从简单的3个节点的集群情况,分几种情况下采用拒绝策略可以保证先接收到id大的数据情况下的一致,但是对于那种先接收到id小的情况,我们的拒绝策略完全无效,那么有个思路就是,假如可以设计成一致,那么不就可以实现即使先收到id小的情况也可以保证一致性吗?&/p&&p&
那么开始下,zk的选主从QuorumPeer这个类的run()开始看起,刚开始的那部分都是注册jmx方便管理,可以忽略掉。
&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&k&&case&/span& &span class=&n&&LOOKING&/span&&span class=&o&&:&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&Boolean&/span&&span class=&o&&.&/span&&span class=&na&&getBoolean&/span&&span class=&o&&(&/span&&span class=&s&&&readonlymode.enabled&&/span&&span class=&o&&))&/span& &span class=&c1&&//判断是否是只读模式&/span&
&span class=&o&&...&/span&&span class=&c1&&//创建只能zkserver&/span&
&span class=&n&&Thread&/span& &span class=&n&&roZkMgr&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&n&&Thread&/span&&span class=&o&&()&/span& &span class=&o&&{&/span& &span class=&c1&&//设计在随机两秒内启动&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&run&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&try&/span& &span class=&o&&{&/span&
&span class=&c1&&// lower-bound grace period to 2 secs&/span&
&span class=&n&&sleep&/span&&span class=&o&&(&/span&&span class=&n&&Math&/span&&span class=&o&&.&/span&&span class=&na&&max&/span&&span class=&o&&(&/span&&span class=&mi&&2000&/span&&span class=&o&&,&/span& &span class=&n&&tickTime&/span&&span class=&o&&));&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&ServerState&/span&&span class=&o&&.&/span&&span class=&na&&LOOKING&/span&&span class=&o&&.&/span&&span class=&na&&equals&/span&&span class=&o&&(&/span&&span class=&n&&getPeerState&/span&&span class=&o&&()))&/span& &span class=&o&&{&/span&
&span class=&n&&roZk&/span&&span class=&o&&.&/span&&span class=&na&&startup&/span&&span class=&o&&();&/span& &span class=&c1&&//这部分是启动一些会话管理,同步线程处理器,预处理线程处理器&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span& &span class=&k&&catch&/span& &span class=&o&&(&/span&&span class=&n&&InterruptedException&/span& &span class=&n&&e&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&LOG&/span&&span class=&o&&.&/span&&span class=&na&&info&/span&&span class=&o&&(&/span&&span class=&s&&&Interrupted while attempting to start ReadOnlyZooKeeperServer, not started&&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span& &span class=&k&&catch&/span& &span class=&o&&(&/span&&span class=&n&&Exception&/span& &span class=&n&&e&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&LOG&/span&&span class=&o&&.&/span&&span class=&na&&error&/span&&span class=&o&&(&/span&&span class=&s&&&FAILED to start ReadOnlyZooKeeperServer&&/span&&span class=&o&&,&/span& &span class=&n&&e&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&span class=&o&&};&/span&
&span class=&o&&...&/span&
&span class=&n&&setCurrentVote&/span&&span class=&o&&(&/span&&span class=&n&&makeLEStrategy&/span&&span class=&o&&().&/span&&span class=&na&&lookForLeader&/span&&span class=&o&&());&/span& &span class=&c1&&//采用选主策略来进行选主&/span&
&/code&&/pre&&/div&&p&
对于选主来说lookForLeader()定制了选主的策略,将以FastLeaderElection来简单地举例,顺着这个方法,我们可以看到&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&synchronized&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&){&/span&
&span class=&n&&logicalclock&/span&&span class=&o&&++;&/span& &span class=&c1&&//更新逻辑时间&/span&
&span class=&n&&updateProposal&/span&&span class=&o&&(&/span&&span class=&n&&getInitId&/span&&span class=&o&&(),&/span& &span class=&n&&getInitLastLoggedZxid&/span&&span class=&o&&(),&/span& &span class=&n&&getPeerEpoch&/span&&span class=&o&&());&/span&
&span class=&c1&&//更新选票,把票投给自己&/span&
&span class=&n&&sendNotifications&/span&&span class=&o&&();&/span& &span class=&c1&&//通知下其它节点&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&
我们可以看到logicalclock这个逻辑时钟的表示,它通过一个变量来表示经历了几轮地选举,假如出现logicalclock小于接收到的其它节点的信息,我们其实可以假想自己本身的这个peer可能被网络分区过,造成错过了,则需要同步到选举情况,否则,可能就会出现自己的信息还是过期的数据。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&
&span class=&k&&while&/span& &span class=&o&&((&/span&&span class=&n&&self&/span&&span class=&o&&.&/span&&span class=&na&&getPeerState&/span&&span class=&o&&()&/span& &span class=&o&&==&/span& &span class=&n&&ServerState&/span&&span class=&o&&.&/span&&span class=&na&&LOOKING&/span&&span class=&o&&)&/span& &span class=&o&&&&&/span&
&span class=&o&&(!&/span&&span class=&n&&stop&/span&&span class=&o&&))&/span&
&span class=&c1&&//当节点还处于looking状态时则不断执行&/span&
&span class=&n&&Notification&/span& &span class=&n&&n&/span& &span class=&o&&=&/span& &span class=&n&&recvqueue&/span&&span class=&o&&.&/span&&span class=&na&&poll&/span&&span class=&o&&(&/span&&span class=&n&&notTimeout&/span&&span class=&o&&,&/span&
&span class=&n&&TimeUnit&/span&&span class=&o&&.&/span&&span class=&na&&MILLISECONDS&/span&&span class=&o&&);&/span&&span class=&c1&&//从收到的信息队列中等待取数据&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&n&/span& &span class=&o&&==&/span& &span class=&kc&&null&/span&&span class=&o&&){&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&na&&haveDelivered&/span&&span class=&o&&()){&/span& &span class=&c1&&//假如暂未取到数据,并且已经发送过了,那应该采用积极地发送&/span&
&span class=&n&&sendNotifications&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span& &span class=&k&&else&/span& &span class=&o&&{&/span& &span class=&c1&&//还未完全发送,可以出现分区,那么尝试连接&/span&
&span class=&n&&manager&/span&&span class=&o&&.&/span&&span class=&na&&connectAll&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&
那当拿到节点的反馈数据,那么将会做怎样的process呢?由于从上面的逻辑时钟我们讲到由于如果接收到的小于我们本身的逻辑时钟,那么可能就是网络分区导致的,那么将会直接break;而只有在等于或者大于逻辑时钟的情况下,&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&if (n.electionEpoch & logicalclock) {
logicalclock = n.electionE
recvset.clear();
if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,
getInitId(), getInitLastLoggedZxid(), getPeerEpoch())) {
updateProposal(n.leader, n.zxid, n.peerEpoch);
updateProposal(getInitId(),
getInitLastLoggedZxid(),
getPeerEpoch());
sendNotifications();
&/code&&/pre&&/div&&p& 可以看到当收到的逻辑时钟大于自身时,那么默认就把recvset清空,因为本身自己不是leader了,并且采用totalOrderPredicate验证是否合理,验证的逻辑就是peer的sid是否比自己大,zxid是否比自己大,epoch是否比自己大,如果成功,那就将节点的leader同步到自己,否则还是默认选自己,那为什么还是选自己呢,即使我们可以看到逻辑时钟已经远低于其它节点,这种情况是为了防止假如自己本身是leader,并且已经达到大多数使得zxid增加1,而刚刚的那个结点是之前的少数由于分区未同步的,如果直接同意它的,那么就会导致之前已经同意的事情被反悔了,对于一致性不能忍受。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&n&/span&&span class=&o&&.&/span&&span class=&na&&electionEpoch&/span& &span class=&o&&&&/span& &span class=&n&&logicalclock&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&LOG&/span&&span class=&o&&.&/span&&span class=&na&&isDebugEnabled&/span&&span class=&o&&()){&/span&
&span class=&n&&LOG&/span&&span class=&o&&.&/span&&span class=&na&&debug&/span&&span class=&o&&(&/span&&span class=&s&&&Notification election epoch is smaller than logicalclock. n.electionEpoch = 0x&&/span&
&span class=&o&&+&/span& &span class=&n&&Long&/span&&span class=&o&&.&/span&&span class=&na&&toHexString&/span&&span class=&o&&(&/span&&span class=&n&&n&/span&&span class=&o&&.&/span&&span class=&na&&electionEpoch&/span&&span class=&o&&)&/span&
&span class=&o&&+&/span& &span class=&s&&&, logicalclock=0x&&/span& &span class=&o&&+&/span& &span class=&n&&Long&/span&&span class=&o&&.&/span&&span class=&na&&toHexString&/span&&span class=&o&&(&/span&&span class=&n&&logicalclock&/span&&span class=&o&&));&/span&
&span class=&o&&}&/span&
&span class=&k&&break&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&针对于逻辑时钟小的,那么肯定是得丢弃的,因为不可能存在同一时空的,这采用的是相对地来看&/p&&p&&/p&
////在讲zk的选主前,先普及几个概念,即分布式的逻辑时钟,paxos算法的简单普及 分布式系统中,由于是分布在不同的机器上,完全无法使用物理上的时钟来表示,仅能依赖于网络的通讯,而由于通讯之间存在某种因果关系。在分布式系统中的事件存在潜在地因果关…
&figure&&img src=&https://pic4.zhimg.com/v2-af141dfb58df782df814_b.jpg& data-rawwidth=&1200& data-rawheight=&551& class=&origin_image zh-lightbox-thumb& width=&1200& data-original=&https://pic4.zhimg.com/v2-af141dfb58df782df814_r.jpg&&&/figure&&p&前两天去了去哪网面试,经过两个多小时的面试(三轮技术面试+一轮HR面试)之后成功拿到了offer,现在把面试的经历以及技术问题写下来,供小伙伴们参考,学习。&/p&&p&&br&&/p&&h2&一面&/h2&&p&一面总结一个词就是&b&广泛&/b&。&/p&&p&顾名思义此时主要考察的就是你对知识了解的是否足够多,足够全面。&/p&&p&一面问的问题并不是很深入。在你自我介绍的时候他会看你简历上写的掌握的技术内容以及项目中用到的技术,并且根据这些来提问。&/p&&p&主要技术问题:&/p&&ol&&li&简单介绍一下HashMap (其中包括底层数据结构、为什么默认长度的为16、线程安全问题等)&/li&&li&介绍一下红黑树 (因为HashMap在JDK1.8中数据结构加入了红黑树)&/li&&li&简单说一下ConcurrentHashMap (主要是与HashMap的区别、怎么实现线程安全的)&/li&&li&说一下数据库的事务以及数据库的隔离级别&/li&&li&是否了解数据库索引 (这里主要问的是BTree以及B+Tree的区别、B+Tree的特性)&/li&&li&介绍一下悲观锁、乐观锁 (区别、什么时候用等)&/li&&li&如果现在只有一张火车票,怎么让所有人都看见但是只有一个人能购买成功 (这里就是悲观锁乐观锁的应用处理并发问题)&/li&&li&简单介绍一下AOP、实现动态代理的方式&/li&&li&写一下快速排序/堆排序/归并排序的伪代码并说明时间复杂度 (伪代码也可以不用写,但是一定要说明白流程;时间复杂度也要会)&/li&&li&说明一下哪种排序是稳定的&/li&&li&简单说一下垃圾回收机制&/li&&/ol&&p&&br&&/p&&h2&二面&/h2&&p&二面总结一个词就是&b&深入&/b&。&/p&&p&此时主要就是考察你对知识是否了解的足够细致,足够深。&/p&&p&可以看到一面的问题大多你经常读一读文章应该都可了解,并不需要你知道的非常深入,有一些能说出概念意思就可以,但是二面就会问你源码、原理等。此时需要你有一定的代码量。不仅如此,二面还会考察你的自学能力,问的问题甚至涉及到了翻墙。。&/p&&p&主要技术问题:&/p&&ol&&li&你看过JAVA源码么?介绍一下&/li&&li&说一下Dom4J以及SAX的区别,什么时候用,怎么用&/li&&li&说一下Maven,为什么要用Maven&/li&&li&git常用指令&/li&&li&用过Linux么?&/li&&li&说一下线程池的源码,里面的变量都是什么意思&/li&&li&介绍JVM内存分区,以及各个区中的垃圾回收机制&/li&&li&是否了解双亲委派机制模型(问的就是类加载器)&/li&&li&介绍一下NIO,怎么使用NIO&/li&&li&一系列的并发问题&/li&&li&拿出一个简历上你最喜欢的项目,详细介绍一下技术以及问题的解决&/li&&li&如果给你一个新框架,你会怎么去学习。&/li&&li&会翻墙么?&/li&&li&喜欢读书么?最近在读什么书?说出书的名字&/li&&/ol&&p&&br&&/p&&h2&三面&/h2&&p&三面总结一个词就是&b&思想。&/b&&/p&&p&一面二面把主要的技术问题也问的差不多了,三面问的问题就涉及到的你的逻辑思想层面。问的问题你会感觉和技术不搭边甚至有点千奇百怪。问题很少但是要难回答的多。&/p&&p&主要问题:&/p&&ol&&li&最近在学习什么知识么?你对什么知识感兴趣呢?&/li&&li&对于大数据你怎么看?(这个问题是我回答第一个问题引出来的,如果你不说的话可能不会问你)&/li&&li&你有两台服务器是相互协作工作的(一台维护,另一台运行),你怎么处理请求以及静态数据问题?&/li&&li&有两台服务器同时购买同一件东西,不在数据库端、服务器端加锁,怎么处理并发。&/li&&li&如果让你设计一块缓存,你会怎么设计?(这个问题我感觉很难,他会问你数据结构以及时间复杂度。而且缓存存入的东西不能有逻辑运算,没有逻辑运算就意味着你在调用的时候怎么对准确的调用到存入的信息。并且在内存满了的时候你会怎么设计清除掉垃圾数据。)&/li&&/ol&&p&&br&&/p&&h2&四面(HR面)&/h2&&p&如果走到这一步,恭喜你,你离入职的门槛只剩临门一脚了。在这里只要你不浪,不跳。一般都能过,HR会跟你聊聊天问你有没有女朋友(这个问题真的太难受了)。然后说一下加班没有加班费一切跟着项目组走有没有转正等一系列情况。。。经过一系列讨价还价斗智斗勇之后,你就会加到HR小姐姐微信然后等着offer就可以啦~&/p&&p&&br&&/p&&p&因为很多问题都不是一句两句能说清楚的,在这里就不贴答案了, 以后经过整理之后我争取把一些博客链接等发在下面供大家参考。除了上述问题,他还可能问到集群、Spring Boot、Redis等问题,这些是根据你简历写的技术内容改变的。&/p&&p&暂时就是有些,想到关键的我会继续补充。大家加油~&/p&&figure&&img src=&https://pic1.zhimg.com/v2-a5c0ac683af5e57a085ee0a3a61d7708_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&301& data-rawheight=&311& class=&content_image& width=&301&&&/figure&&p&&br&&/p&&hr&&p&谢谢大家的关注评论点赞与收藏!经过两天的工(mai)作(meng),我休息了~,今天吧上面一些问题我认为解答的很好的连接整理出来供大家参考。大家如果有更好的文章欢迎在评论区留言,谢谢。&/p&&p&&br&&/p&&ul&&li&关于HashMap:&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&Java 8系列之重新认识HashMap&/a&&/li&&li&关于ConcurretHashMap:&a href=&https://link.zhihu.com/?target=http%3A//www.importnew.com/22007.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ConcurrentHashMap总结 - ImportNew&/a&&/li&&li&关于红黑树:&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&红黑树深入剖析及Java实现&/a&&/li&&li&关于B树,数据库索引:&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/wl/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&数据库常见索引解析(B树,B-树,B+树,B*树,位图索引,Hash索引) - CSDN博客&/a&&/li&&li&关于数据库事务:&a href=&https://link.zhihu.com/?target=https%3A//www.cnblogs.com/gaopeng527/p/5257009.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&关于数据库事务、隔离级别、锁的理解与整理(转) - ~风轻云淡~ - 博客园&/a&&/li&&li&关于悲观锁和乐观锁:这个我就不贴链接了,因为这个要看的东西很多,还要了解乐观锁重试次数等问题,我建议大家多看一些博客了解一下。&b&不能为了面试去了解表面知识,这个知识很重要!&/b&&/li&&li&关于排序:&a href=&https://link.zhihu.com/?target=https%3A//www.cnblogs.com/eniac12/p/5329396.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&常用排序算法总结(一) - SteveWang - 博客园&/a&&/li&&li&关于垃圾回收:&a href=&https://link.zhihu.com/?target=http%3A//www.cnblogs.com/hnrainll/p/3410042.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java 内存区域和GC机制 - Leo Chin - 博客园&/a&&/li&&li&关于XML解析的区别:&a href=&https://link.zhihu.com/?target=http%3A//blog.csdn.net/jzhf2012/article/details/8532873& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&解析xml的4种方法详解 - CSDN博客&/a&&/li&&/ul&&p&&br&&/p&&p&以上就是我整理出来的一些文章,是我在各个平台比较之后个人感觉比较详细一点的。还有一些不是没有整理,是因为那些不是几篇博客什么的就能弄懂的,需要一些时间去学习。&/p&&p&&br&&/p&&p&另外附上几点建议:&/p&&ul&&li&&b&关于并发,我强烈建议大家看看《&i&阿里巴巴&/i&Java开发&i&手册&/i&》中关于并发的规范。&/b&(本来不想说,因为有可能被黑这本书的人喷,但是我真的感觉在并发等方面写的很好!)&/li&&li&&b&一定要多实践,也就是多敲代码!&/b&看10遍也不如你按照自己的理解敲出来一遍&/li&&li&&b&或许你现在知道的不深,但是你一定要知道的多!&/b&&/li&&li&&b&给别人多讲。&/b&&/li&&/ul&
前两天去了去哪网面试,经过两个多小时的面试(三轮技术面试+一轮HR面试)之后成功拿到了offer,现在把面试的经历以及技术问题写下来,供小伙伴们参考,学习。 一面一面总结一个词就是广泛。顾名思义此时主要考察的就是你对知识了解的是否足够多,足够全面。…
&h2&概念&/h2&&p&&b&事务ID&/b&&br&事务ID是一个递增的整数,唯一的标识一个事务。ID的大小可以用来表示事务的串行化顺序,用于事务可见性的判断。&/p&&p&&b&多版本存储&/b&&br&MySQL InnoDB实现了多版本并发控制(MVCC),在多版本存储上,MySQL采用从新到旧(Newest To Oldest)的版本链。B+Tree叶结点上,始终存储的是最新的数据(可能是还未提交的数据)。而旧版本数据,通过UNDO记录(做DELTA)存储在回滚段(Rollback Segment)里。每一条记录都会维护一个ROW HEADER元信息,存储有创建这条记录的事务ID,一个指向UNDO记录的指针。通过最新记录和UNDO信息,可以还原出旧版本的记录。&/p&&p&如下图, V1被一个事务更新为V2,V2被另一个事务更新为V3,Δ1存储V1到V2的更新,Δ2存储V2到V3的更新。此时,如果一个事条定位到B+Tree叶子节点的记录V3,则通过V3+Δ2可以还原出V2,通过V3+Δ2+Δ1可以还原出V1。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-891c15ccbbae528ed243f_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&631& data-rawheight=&280& class=&origin_image zh-lightbox-thumb& width=&631& data-original=&https://pic2.zhimg.com/v2-891c15ccbbae528ed243f_r.jpg&&&/figure&&p&&b&ReadView (或者可以称之为Snapshot)&/b&&/p&&p&ReadView是某一个时间点,事务执行状态的一个快照,可以用来判断事务的可见性。ReadView的基本结构如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&ReadView {
creator_trx_id
low_limit_id
up_limit_id
&/code&&/pre&&/div&&p&&b&creator_trx_id&/b& 创建这个ReadView的事务ID&/p&&p&&b&low_limit_id&/b& 所有事务ID大于或等于low_limit_id对当前事务都不可见&/p&&p&&b&up_limit_id&/b& 所有事务ID严格小于up_limit_id的事务对当前事务可见&/p&&p&&b&ids&/b& 未提交的事务ID列表&/p&&p&&b&可见性的判断&/b&&/p&&p&事务通过用当前事务(或语句,取决于隔离级别)的RaadView来判断一个事务id的操作是否对当前事务可见。判断可见性的伪代码如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&IsVisible(trx_id)
if (trx_id == creator_trx_id)
// 当前事务
else if (trx_id & up_limit_id)
// ReadView创建时, 事务已提交
else if (trx_id &= low_limit_id)
// ReadView创建时,事务还未被创建
else if (trx_id is in m_ids)
// ReadView创建时,事务正在执行,但未提交
return false
// ReadView创建时, 事务已提交
&/code&&/pre&&/div&&h2&不同隔离级别的实现&/h2&&p&&b&可串行化(Serializable)&/b&&br&在可串行化级别上,MySQL执行S2PL并发控制协议, 一阶段申请,一阶段释放。读写都要加锁。&/p&&p&&b&可重复读(Repeatable Read)&/b&&br&可重复读是MySQL默认的隔离级别,理论上说应该称作快照(Snapshot)隔离级别。读不加锁,只有写才加锁,读写互不阻塞,并发度相对于可串行化级别要高,但会有Write Skew异常。&/p&&p&事务在开始时创建一个ReadView,当读一条记录时,会遍历版本链表,通过当前事务的ReadView判断可见性,找到第一个对当前事务可见的版本,读这个版本。&/p&&p&对于写操作,包括Locking Read(SELECT ... FOR UPDATE), UPDATE, DELETE,需要加写锁。根据谓词条件上索引使用情形,锁定有不同的方式:&/p&&p&1)有索引:&br&对于索引上有唯一约束且为等值条件的情形,不用GAP LOCK,只锁定索引记录。对于其它情形,使用GAP LOCK,相当于谓词锁。&br&2)没有索引:&br&由于MySQL没有实现通用的谓词锁,这时就相当于锁全表。&/p&&p&需要特殊说明的是,MySQL在可重复读级别对于更新冲突的处理有点特殊。MySQL支持Write Committed,可以更新在事务执行期间提交的记录。这点和PostgreSQL不同,PostgreSQL发生更新冲突要回滚。MySQL这个设计,减小了回滚率,但导致在可重复读级别下,并发的写入可能会发生异常。比如下面的例子,两个并行的事务执行后,发生了更新丢失异常(从上到下表示执行顺序,SQL仅用于说明这个问题,无实际意义,改写SQL可以规避这个问题)&/p&&div class=&highlight&&&pre&&code class=&language-mysql&&&span class=&n&&Transaction&/span& &span class=&n&&T1&/span&
&span class=&o&&|&/span&
&span class=&n&&Transaction&/span& &span class=&n&&T2&/span&
&span class=&n&&start&/span& &span class=&n&&transaction&/span&&span class=&p&&;&/span&
&span class=&o&&|&/span&
&span class=&k&&select&/span& &span class=&n&&v&/span& &span class=&k&&into&/span& &span class=&o&&@&/span&&span class=&n&&x&/span& &span class=&k&&from&/span& &span class=&n&&t&/span& &span class=&k&&where&/span& &span class=&n&&k&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span& &span class=&o&&|&/span& &span class=&n&&start&/span& &span class=&n&&transaction&/span&&span class=&p&&;&/span&
&span class=&o&&|&/span& &span class=&k&&select&/span& &span class=&n&&v&/span& &span class=&k&&into&/span& &span class=&o&&@&/span&&span class=&n&&x&/span& &span class=&k&&from&/span& &span class=&n&&t&/span& &span class=&k&&where&/span& &span class=&n&&k&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&o&&|&/span& &span class=&k&&update&/span& &span class=&n&&t&/span& &span class=&kt&&set&/span& &span class=&n&&v&/span& &span class=&o&&=&/span& &span class=&o&&@&/span&&span class=&n&&x&/span&&span class=&o&&*&/span&&span class=&mi&&10&/span& &span class=&k&&where&/span& &span class=&n&&k&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&o&&|&/span& &span class=&n&&commit&/span&&span class=&p&&;&/span&
&span class=&k&&update&/span& &span class=&n&&t&/span& &span class=&kt&&set&/span& &span class=&n&&v&/span& &span class=&o&&=&/span& &span class=&o&&@&/span&&span class=&n&&x&/span&&span class=&o&&*&/span&&span class=&mi&&10&/span& &span class=&k&&where&/span& &span class=&n&&k&/span& &span class=&o&&=&/span& &span class=&mi&&1&/span&&span class=&p&&;&/span&
&span class=&o&&|&/span&
&span class=&n&&commit&/span&&span class=&p&&;&/span&
&span class=&o&&|&/span&
&/code&&/pre&&/div&&p&T1,T2执行前:&/p&&div class=&highlight&&&pre&&code class=&language-text&&mysql& select *
+---+------+
+---+------+
+---+------+
&/code&&/pre&&/div&&p&T1,T2执行后:&/p&&div class=&highlight&&&pre&&code class=&language-text&&mysql& select *
+---+------+
+---+------+
+---+------+
&/code&&/pre&&/div&&p&&b&读已提交(Read Committed)&/b&&br&MySQL的读已提交实际是语句级别快照。&/p&&p&与可重复读级别主要有两点不同:&br&1)获得ReadView的时机。每个语句开始执行时,获得ReadView,可见性判断是基于语句级别的ReadView。读的策略与可重复读类似。&/p&&p&2)写锁的使用方式。这里不需要GAP LOCK,只使用记录锁。并且事务只持有被UPDATE/DELETE记录的写锁(可重复读需要保留全部写锁直到事务结束,而读已提交只保留真正更改的)。&/p&&p&&b&读未提交(Read Uncommitted)&/b&&br&读最新的数据,不管这条记录是不是已提交。不会遍历版本链,少了查找可见的版本的步骤。这样可能会导致脏读。&/p&&p&对写仍需要锁定,策略和读已提交类似,避免脏写。&/p&
概念事务ID 事务ID是一个递增的整数,唯一的标识一个事务。ID的大小可以用来表示事务的串行化顺序,用于事务可见性的判断。多版本存储 MySQL InnoDB实现了多版本并发控制(MVCC),在多版本存储上,MySQL采用从新到旧(Newest To Oldest)的版本链。B+Tree…
&figure&&img src=&https://pic3.zhimg.com/v2-5b9bdb062d4d6a1ed4627_b.jpg& data-rawwidth=&4076& data-rawheight=&2712& class=&origin_image zh-lightbox-thumb& width=&4076& data-original=&https://pic3.zhimg.com/v2-5b9bdb062d4d6a1ed4627_r.jpg&&&/figure&&h2&&b&0x00 前言&/b&&/h2&&p&机缘巧合,最近公司突然要搞一波大量数据的分析。属于客流类的分析。&/p&&p&数据量级也还算不错,经过 gzip 压缩,接近 400 个 点位的 SQL 文件 (MySQL innoDB),大小接近 100GB 左右,原始记录数据估测在 180 亿左右。&/p&&p&解压后…… 差不多一个 T 吧。&/p&&p&如果是人民币玩家,自然是直接购置几十台高配置机器,做个 mysql shard 或者直接上大数据全家桶比如 hadoop 和 hive 之类,让程序员去往死里折腾吧。&/p&&blockquote&嗯,然而对于我这种非人民币玩家,就要用单机硬扛。&/blockquote&&p&那就硬扛呗。&/p&&p&我手上的机器配置如下:&/p&&ul&&li&局域网服务器 ( Ubuntu 16.04 LTS )&/li&&ul&&li&Xeon(R) CPU E3-1225 v5 @ 3.30GHz&/li&&li&16G 内存&/li&&li&1T 硬盘&/li&&/ul&&/ul&&p&&br&&/p&&ul&&li&苹果电脑 2016 年 15 寸 最高配&/li&&ul&&li&1T 硬盘&/li&&li&i7 四核&/li&&/ul&&/ul&&p&&br&&/p&&h2&&b&0x01 准备数据阶段&/b&&/h2&&p&用低配机器分析大数据的&b&首要原则&/b&,就是&b&不要分析大数据&/b&。&/p&&p&何也?&/p&&blockquote&就是&b&尽可能的抽取所得结论所需分析数据的最小超集&/b&&/blockquote&&p&小机器是无法完成海量计算的,但通过一定的过滤和筛选可以将数据筛选出到一台机器能扛得住的计算量。从而达到可以可以分析海量数据的目的。&/p&&h2&&b&1.1 将数据导入 MySQL 中&/b&&/h2&&p&我们先不管三七二十一,既然给了 SQL 文件,肯定要入库的,那么问题来了:&/p&&blockquote&将大象关进冰箱要几个步骤&/blockquote&&p&将数据导入数据库中需要几个步骤&/p&&p&或者说,如何更快的导入 400 张不同表的数据。&/p&&p&大致步骤如下:&/p&&ul&&li&新增硬盘,并初始化&/li&&li&配置 MySQL 的 datadir 到新增硬盘上&/li&&li&导入数据 (PV & MySQL)&/li&&/ul&&h2&&b&新增硬盘,并初始化&/b&&/h2&&p&首先,&b&购买并插入硬盘&/b&&/p&&p&使用 lshw 查看硬盘信息&/p&&div class=&highlight&&&pre&&code class=&language-abap&&&span&&/span&&span class=&nv&&root&/span&&span class=&err&&@&/span&&span class=&nv&&ubuntu&/span&&span class=&p&&:&/span&&span class=&err&&~#&/span& &span class=&nv&&lshw&/span& &span class=&o&&-&/span&&span class=&nv&&C&/span& &span class=&nv&&disk&/span&
&span class=&o&&*-&/span&&span class=&nv&&disk&/span&
&span class=&nv&&description&/span&&span class=&p&&:&/span& &span class=&nv&&SCSI&/span& &span class=&nv&&Disk&/span&
&span class=&nv&&product&/span&&span class=&p&&:&/span& &span class=&nv&&My&/span& &span class=&nv&&Passport&/span& &span class=&mi&&25&/span&&span class=&nv&&E2&/span&
&span class=&nv&&vendor&/span&&span class=&p&&:&/span& &span class=&nv&&WD&/span&
&span class=&nv&&physical&/span& &span class=&k&&id&/span&&span class=&p&&:&/span& &span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&
&span class=&nv&&bus&/span& &span class=&nv&&info&/span&&span class=&p&&:&/span& &span class=&nv&&scsi&/span&&span class=&err&&@&/span&&span class=&mi&&7&/span&&span class=&p&&:&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&
&span class=&nv&&logical&/span& &span class=&nv&&name&/span&&span class=&p&&:&/span& &span class=&p&&/&/span&&span class=&nv&&dev&/span&&span class=&p&&/&/span&&span class=&nv&&sdb&/span&
&span class=&nv&&version&/span&&span class=&p&&:&/span& &span class=&mi&&4004&/span&
&span class=&nv&&serial&/span&&span class=&p&&:&/span& &span class=&nv&&WX888888HALK&/span&
&span class=&nv&&size&/span&&span class=&p&&:&/span& &span class=&mi&&3725&/span&&span class=&nv&&GiB&/span& &span class=&p&&(&/span&&span class=&mi&&4&/span&&span class=&nv&&TB&/span&&span class=&p&&)&/span&
&span class=&nv&&capabilities&/span&&span class=&p&&:&/span& &span class=&nv&&gpt&/span&&span class=&o&&-&/span&&span class=&mi&&1&/span&&span class=&p&&.&/span&&span class=&mi&&00&/span& &span class=&nv&&partitioned&/span& &span class=&nv&&partitioned&/span&&span class=&p&&:&/span&&span class=&nv&&gpt&/span&
&span class=&nv&&configuration&/span&&span class=&p&&:&/span& &span class=&nv&&ansiversion&/span&&span class=&o&&=&/span&&span class=&mi&&6&/span& &span class=&nv&&guid&/span&&span class=&o&&=&/span&&span class=&mi&&88&/span&&span class=&nv&&e88888&/span&&span class=&o&&-&/span&&span class=&mi&&422&/span&&span class=&nv&&d&/span&&span class=&o&&-&/span&&span class=&mi&&49&/span&&span class=&nv&&f0&/span&&span class=&o&&-&/span&&span class=&mi&&9&/span&&span class=&nv&&ba9&/span&&span class=&o&&-&/span&&span class=&mi&&221&/span&&span class=&nv&&db75fe4b4&/span& &span class=&nv&&logicalsectorsize&/span&&span class=&o&&=&/span&&span class=&mi&&512&/span& &span class=&nv&&sectorsize&/span&&span class=&o&&=&/span&&span class=&mi&&4096&/span&
&span class=&o&&*-&/span&&span class=&nv&&disk&/span&
&span class=&nv&&description&/span&&span class=&p&&:&/span& &span class=&nv&&ATA&/span& &span class=&nv&&Disk&/span&
&span class=&nv&&product&/span&&span class=&p&&:&/span& &span class=&nv&&WDC&/span& &span class=&nv&&WD10EZEX&/span&&span class=&o&&-&/span&&span class=&mi&&08&/span&&span class=&nv&&W&/span&
&span class=&nv&&vendor&/span&&span class=&p&&:&/span& &span class=&nv&&Western&/span& &span class=&nv&&Digital&/span&
&span class=&nv&&physical&/span& &span class=&k&&id&/span&&span class=&p&&:&/span& &span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&
&span class=&nv&&bus&/span& &span class=&nv&&info&/span&&span class=&p&&:&/span& &span class=&nv&&scsi&/span&&span class=&err&&@&/span&&span class=&mi&&0&/span&&span class=&p&&:&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&
&span class=&nv&&logical&/span& &span class=&nv&&name&/span&&span class=&p&&:&/span& &span class=&p&&/&/span&&span class=&nv&&dev&/span&&span class=&p&&/&/span&&span class=&nv&&sda&/span&
&span class=&nv&&version&/span&&span class=&p&&:&/span& &span class=&mi&&1&/span&&span class=&nv&&A01&/span&
&span class=&nv&&serial&/span&&span class=&p&&:&/span& &span class=&nv&&WD&/span&&span class=&o&&-&/span&&span class=&nv&&WCU&/span&
&span class=&nv&&size&/span&&span class=&p&&:&/span& &span class=&mi&&931&/span&&span class=&nv&&GiB&/span& &span class=&p&&(&/span&&span class=&mi&&1&/span&&span class=&nv&&TB&/span&&span class=&p&&)&/span&
&span class=&nv&&capabilities&/span&&span class=&p&&:&/span& &span class=&nv&&partitioned&/span& &span class=&nv&&partitioned&/span&&span class=&p&&:&/span&&span class=&nv&&dos&/span&
&span class=&nv&&configuration&/span&&span class=&p&&:&/span& &span class=&nv&&ansiversion&/span&&span class=&o&&=&/span&&span class=&mi&&5&/span& &span class=&nv&&logicalsectorsize&/span&&span class=&o&&=&/span&&span class=&mi&&512&/span& &span class=&nv&&sectorsize&/span&&span class=&o&&=&/span&&span class=&mi&&4096&/span& &span class=&nv&&signature&/span&&span class=&o&&=&/span&&span class=&nv&&f1b42036&/span&
&span class=&o&&*-&/span&&span class=&nv&&cdrom&/span&
&span class=&nv&&description&/span&&span class=&p&&:&/span& &span class=&nv&&DVD&/span& &span class=&nv&&reader&/span&
&span class=&nv&&product&/span&&span class=&p&&:&/span& &span class=&nv&&DVDROM&/span& &span class=&nv&&DH1XXX8SH&/span&
&span class=&nv&&vendor&/span&&span class=&p&&:&/span& &span class=&nv&&PLDS&/span&
&span class=&nv&&physical&/span& &span class=&k&&id&/span&&span class=&p&&:&/span& &span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&
&span class=&nv&&bus&/span& &span class=&nv&&info&/span&&span class=&p&&:&/span& &span class=&nv&&scsi&/span&&span class=&err&&@&/span&&span class=&mi&&5&/span&&span class=&p&&:&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&&span class=&p&&.&/span&&span class=&mi&&0&/span&
&span class=&nv&&logical&/span& &span class=&nv&&name&/span&&span class=&p&&:&/span& &span class=&p&&/&/span&&span class=&nv&&dev&/span&&span class=&p&&/&/span&&span class=&nv&&cdrom&/span&
&span class=&nv&&logical&/span& &span class=&nv&&name&/span&&span class=&p&&:&/span& &span class=&p&&/&/span&&span class=&nv&&dev&/span&&span class=&p&&/&/span&&span class=&nv&&dvd&/span&
&span class=&nv&&logical&/span& &span class=&nv&&name&/span&&span class=&p&&:&/span& &span class=&p&&/&/span&&span class=&nv&&dev&/span&&span class=&p&&/&/span&&span class=&nv&&sr0&/span&
&span class=&nv&&version&/span&&span class=&p&&:&/span& &span class=&nv&&ML31&/span&
&span class=&nv&&capabilities&/span&&span class=&p&&:&/span& &span class=&nv&&removable&/span& &span class=&nv&&audio&/span& &span class=&nv&&dvd&/span&
&span class=&nv&&configuration&/span&&span class=&p&&:&/span& &span class=&nv&&ansiversion&/span&&span class=&o&&=&/span&&span class=&mi&&5&/span& &span class=&nv&&status&/span&&span class=&o&&=&/span&&span class=&nv&&nodisc&/span&
&/code&&/pre&&/div&&p&&br&&/p&&p&使用 fdisk 格式化硬盘,并且分区&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&fdisk /dev/sdb
sudo mkfs -t ext4 /dev/sdb1
mkdir -p /media/mynewdrive
vim /etc/fstab
# /dev/sdb1
/media/mynewdrive
# 直接挂载所有,或者 reboot
&/code&&/pre&&/div&&p&至此为止,硬盘就格式化完成了。&/p&&blockquote&关于安装硬盘,可以参考 &a href=&http://link.zhihu.com/?target=https%3A//help.ubuntu.com/community/InstallingANewHardDrive& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&help.ubuntu.com/communi&/span&&span class=&invisible&&ty/InstallingANewHardDrive&/span&&span class=&ellipsis&&&/span&&/a&&/blockquote&&h2&&b&配置 MySQL&/b&&/h2&&p&篇幅有限,只简介具体在 Ubuntu 16.04 上面 配置 MySQL 的 DataDIR ,省去安装和基本登录认证的配置。&/p&&p&mysql 在 ubuntu 下面默认的路径如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&/var/lib/mysql/
&/code&&/pre&&/div&&p&我们开始配置 DataDIR&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&systemctl stop mysql
rsync -av /var/lib/mysql /mnt/volume-nyc1-01
mv /var/lib/mysql /var/lib/mysql.bak
vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 修改至 datadir=/mnt/volume-nyc1-01/mysql
vim /etc/apparmor.d/tunables/alias
# alias /var/lib/mysql/ -& /mnt/volume-nyc1-01/mysql/
sudo systemctl restart apparmor
vim /usr/share/mysql/mysql-systemd-start
if [ ! -d /var/lib/mysql ] && [ ! -L /var/lib/mysql ]; then
echo &MySQL data dir not found at /var/lib/mysql. Please create one.&
if [ ! -d /var/lib/mysql/mysql ] && [ ! -L /var/lib/mysql/mysql ]; then
echo &MySQL system database not found. Please run mysql_install_db tool.&
sudo mkdir /var/lib/mysql/mysql -p
sudo systemctl restart mysql
# 最后 my.conf 修改相关文件路径
&/code&&/pre&&/div&&blockquote&详细请参考这篇文章 &a href=&http://link.zhihu.com/?target=https%3A//www.digitalocean.com/community/tutorials/how-to-move-a-mysql-data-directory-to-a-new-location-on-ubuntu-16-04& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&digitalocean.com/commun&/span&&span class=&invisible&&ity/tutorials/how-to-move-a-mysql-data-directory-to-a-new-location-on-ubuntu-16-04&/span&&span class=&ellipsis&&&/span&&/a&&/blockquote&&p&将 DataDIR 配置完成之后,就可以导入数据了。嗯,经过这么麻烦的事情之后,我决定下次遇到这种情况首选 Docker 而不是在 Ubuntu Server 上面搞这个。&/p&&blockquote&站在现在看,如果重来的话,我肯定会用 Docker 然后把数据盘挂载到新硬盘到。&/blockquote&&p&比如直接 Docker 命令执行&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&docker run --name some-mysql -v /my/own/datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
&/code&&/pre&&/div&&h2&&b&导入数据 之 MySQL + PV&/b&&/h2&&p&我们使用 mysql 导入脚本的时候,有几种导入方式&/p&&ul&&li&source 命令,然而这个命令容易在数据量很大的时候直接卡掉。(印象中是直接把 sql 文件加载到内存中,然后执行,然而,只要涉及到大量文本打印出来并且执行,速度一定会变慢很多)&/li&&li&mysql 命令&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# mysql 命令的典型导入场景就是这样
mysql -uadmin -p123456 some_db & tb.sql
&/code&&/pre&&/div&&p&加上 PV 命令的话,比较神奇了。有进度条了!!&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# 附加进度条的导入场景
pv -i 1 -p -t -e ./xxxx_probe.sql | mysql -uadmin -p123456 some_db
&/code&&/pre&&/div&&p&然后,可以查看一下磁盘 CPU 内存的占用情况。如果负载(着重注意 IO,内存)还不够满,使用 tmux 多开几个进程导入数据。&/p&&p&因为每个 SQL 文件对应的表不一样,所以多开几个进程批量 insert 的话并不会锁表,这样可以显著提升导入速度。&/p&&h2&&b&1.2 导出数据&/b&&/h2&&p&既然已经导入了数据,为什么需要导出数据呢?&/p&&p&因为数据量比较大,需要进行初步清洗。而我们最后肯定使用 Pandas 进行分析,从局域网数据库中读取大量的数据的时候,pandas 速度会非常的慢(具体是因为网络传输速度?)。所以,为了后面分析省事,我批量导出了数据,然后按照我的习惯进行了归类。&/p&&p&在这个过程中,我还进行了一小部分的数据过滤,比如:&/p&&ul&&li&只选取对自己有用的行与列。&/li&&li&化整为零,拆分数据为最小单元的 CSV 文件&/li&&/ul&&h2&&b&只选取对自己有用的行与列&/b&&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&select col_a , col_b from some_table where Acondition and bcondition and col_c in ('xx','yy','zz');
&/code&&/pre&&/div&&p&这里面有一些值得注意的地方&/p&&ul&&li&尽量把简单的判断写在左边。&/li&&li&如果不是反复查询,则没有必要建立索引。直接走全表,筛选出必要的数据存 CSV 即可。&/li&&/ul&&h2&&b&尽量拆分数据为最小单元的 CSV 文件&/b&&/h2&&p&如果按照某类,某段时间进行拆分可以在分析的时候随时取随时分析那就进行拆分。&/p&&p&比如,某个大的 CSV 包含琼瑶里面各种人物情节地点的位置就可以拆分为:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&201712_大明湖畔_夏雨荷_还珠格格_你还记得吗.csv
201711_老街_可云_情深深雨蒙蒙_谁来救我.csv
201710_屋子里_云帆_又见一帘幽梦_你的腿不及紫菱的爱情.csv
&/code&&/pre&&/div&&p&当我们需要取这坨数据的时候,可以直接 glob 一下,然后 sort, 接着二分查找。就可以快速读取这块数据了。&/p&&h2&&b&1.3 校验数据完备性&/b&&/h2&&p&第三方给的数据多多少少会有这些或者那些的问题,一般情况下,可以通过检查数据完备性来尽可能的减少数据的不靠谱性。&/p&&p&我习惯性在这样的表里面详细记录数据完备性的各种参数与进度。&/p&&p&比如:&/p&&ul&&li&数据的提供情况和实际情况&/li&&li&阶段性的记录条数和点位的统计值&/li&&li&max,min,mean,median 用来避免异常值&/li&&li&如果是分年份,则必须要统计每一天的情况,否则也不知道数据的缺失程度。&/li&&/ul&&h2&&b&0x02 分析阶段&/b&&/h2&&p&经过上一步处理,数据的文件总大小大约从 1000GB (uncompressed) -& 30GB 左右 (拆分成若干个文件 compressed) 。每个文件大约是几百兆。&/p&&h2&&b&2.1 性能要点 1:文件系统&/b&&/h2&&p&如果统计逻辑很简单,但是数量多,首选使用读取文件。读取文件进行统计速度是非常快的。(人民币玩家走开)&/p&&p&像 linux 里面的 wc,grep,sort,uniq 在这种场景有时候也能用到。&/p&&p&但,注意,如果文件特别大,一定要迭代器一个一个读取。&/p&&h2&&b&2.2 性能要点 2:化整为零,map reduce filter&/b&&/h2&&p&化整为零这个已经在上面的 1.2 节讲过了。&/p&&p&map/reduce/filter 可以极大的减少代码。&/p&&blockquote&collection 中有个 Counter , 在进行简单代码统计的时候用起来可以极大的减少代码。&/blockquote&&h2&&b&2.3 性能要点 3:进程池的两种作用&/b&&/h2&&p&我们都知道,当 用 Python 执行计算密集的任务时,可以考虑使用多进程来加速:&/p&&p&即&b&为了加速计算&/b&,此为作用一。如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def per_item_calc(item):
df = pd.read.....
# complex calc
return result
with ProcessPoolExecutor(3) as pool:
result_items = pool.map(per_item_calc,all_tobe_calc_items)
reduce_results = ....
&/code&&/pre&&/div&&p&其实进程的销毁本身就可以给我带来第二个作用&b&管理内存&/b&。&/p&&p&具体会在 2.6 中的 DataFrame 里面解释。&/p&&h2&&b&2.4 性能要点 4:List 和 Set , itertools&/b&&/h2&&p&有 400 组 UUID 集合,每个列表数量在 1000000 左右,列表和列表之间重复部分并不是很大。我想拿到去重之后的所有 UUID,应该怎么处理&/p&&p&在去重的时候,自然而然想到了使用集合来处理。&/p&&p&最初的做法是&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&list_of_uuid_set = [ set1 , set2 ... set400 ]
all_uuid_set = reduce(lambda x: x | y, list_of_uuid_set)
&/code&&/pre&&/div&&p&1 小时过去了。 突然之间,四下里万籁无声。公司内外聚集数百之众,竟不约而同的谁都没有出声,便有人想说话的,也为这寂静的气氛所慑,话到嘴边都缩了回去。似乎硬盘的指示灯也熄灭了,发出轻柔异常的声音。我心中忽想:&/p&&blockquote&小师妹这时候不知在干甚么? 卧槽,程序是不是又卡死了?&/blockquote&&p&SSH 上去 htop 一下机器。发现实存和内存都满了。直觉告诉我,CPython 的集合运算应该是挺耗内存的。&/p&&p&嗯,这怎么行,试试用列表吧。列表占用内存应该是比较小的。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def merge(list1,list2):
list1.append(list2)
return list1
list_of_uuid_list = [ list1 , list2 ... list400 ]
all_uuid_set = set(reduce(merge, list_of_uuid_list))
&/code&&/pre&&/div&&p&1 小时过去了。 我一拍大腿,道:&/p&&blockquote&小师妹这时候不知在干甚么? 卧槽,程序是不是又卡死了?&/blockquote&&p&最后在 StackOverFlow 上找到了更好的解决方案。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&list_of_uuid_list = [ list1 , list2 ... list400 ]
all_uuid_set = set(list(itertools.chain(*list_of_uuid_list)))
&/code&&/pre&&/div&&p&运行一下,5s 不到出了结果(注意,包含了 Set 去重)。&/p&&p&itertools 里还有很多有趣的函数可以使用。&/p&&p&&a href=&http://link.zhihu.com/?target=https%3A//docs.python.org/3/library/itertools.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&docs.python.org/3/libra&/span&&span class=&invisible&&ry/itertools.html&/span&&span class=&ellipsis&&&/span&&/a&&/p&&h2&&b&2.5 性能要点 5:IPython 给性能带来的影响&/b&&/h2&&p&当我们在分析数据的时候,往往使用的是 IPython, 或者 Jupyter Notebook&/p&&p&但是,方便的同时,如果不加以注意的话,就会带来一点点小问题。&/p&&p&比如下划线和双下划线分别存储上一个 CELL 的返回值,和上上个 CELL 的返回值。&/p&&h2&&b&2.6 性能要点 6:DataFrame 带来的 GC 问题&/b&&/h2&&p&DataFrame 是我用 Pandas 的原因,在这次使用 DataFrame 的过程中,还是出现一些头疼的问题的。比如莫名的内存泄露。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def per_item_calc(item):
df = pd.read.....
# complex calc
return result
result_items = []
for item in all_tobe_calc_items:
result_items.append(per_item_calc(item))
reduce_results = ....
&/code&&/pre&&/div&&p&我在 For 循环中读取 DataFrame 赋值给 df, 然后统计出一个结果。按理来说,每次只要一个简单的 result, 每次读取的文件大小一致,同样的会占用接近 2G 内存,而,当我赋值 df 的时候,&b&按理来说,应该是把原先 df 的引用数应该为 0, 会被 gc 掉,又释放了 2G 内存&/b&,所以,是不太可能出现内存不够用的。&/p&&p&运行程序,内存 biubiubiubiu 的增长,当进行到约第 1000 次的循坏的时候,直到 16G 内存占满。&/p&&p&那么显式的 del 一下会不会好一点呢?代码如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def per_item_calc(item):
df = pd.read.....
# complex calc
return result
&/code&&/pre&&/div&&p&似乎好了一点点,但是其实并没有好到哪里去。&/p&&p&然而,和前一次一样,内存 biubiubiubiu 的增长,当进行到约第 1000 次的循坏的时候,直到 16G 内存占满。&/p&&p&只是在读取文件的时候,预先减少了上次循环没有 del 掉的 df. 和上一个想法没有太大区别。除了比上一个方法每次读取文件的提前减少了一个多 G 的内存。&/p&&p&查找相关资料,涉及到 Python 里面的 Pandas GC 的资料并不多,稍微整理一下,如下:&/p&&blockquote&Python 程序 在 Linux 或者 Mac 中,哪怕是 del 这个对象,Python 依旧 站着茅坑不拉屎 就是不把内存还给系统,自己先占着,有本事你打死我啊 直到进程销毁。&/blockquote&&p&嗯?这个和我要的东西不一样嘛?具体怎么管理 pandas 里面的 object 的,到底是哪里 GC 不到位呢?还是没有说呀。&/p&&p&参考:&/p&&ul&&li&&a href=&http://link.zhihu.com/?target=https%3A//stackoverflow.com/questions//python-memory-management-dictionary& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&stackoverflow.com/quest&/span&&span class=&invisible&&ions//python-memory-management-dictionary&/span&&span class=&ellipsis&&&/span&&/a&&/li&&li&&a href=&http://link.zhihu.com/?target=http%3A//effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&effbot.org/pyfaq/why-do&/span&&span class=&invisible&&esnt-python-release-the-memory-when-i-delete-a-large-object.htm&/span&&span class=&ellipsis&&&/span&&/a&&/li&&/ul&&p&不过有一点启示了我。&/p&&blockquote&直到进程销毁。&/blockquote&&p&Python 里面不是有个 ProcessPoolExecutor 模块么。&/p&&p&那么问题来了,ProcessPoolExecutor 是动态创建进程并且分配任务的呢,为每一个 item 分配一个进程来运算?还是创建完三个进程之后把 item 分配给空闲进程的进行运算呢?&/p&&ul&&li&如果是后者,则是正经的进程池。似乎 map 过去,除非任务执行完毕或者异常退出,否则进程不销毁。并不能给我们解决 内存泄露 的问题。&/li&&li&如果是前者,则是并不是线程池,但是可以帮我解决内存泄露的问题。&/li&&/ul&&p&你说,进程池肯定是前者咯。可是你在验证之前,这是进程池只是你的从其他语言带来的想法,这是不是一个线程池,是一个什么样子的进程池,如果进程执行过程中挂掉了,这个时候就少了一个线程,会不会再补充一个进程呢??&/p&&p&怎么看验证呢?&/p&&ol&&li&运行程序,进入 Htop 看进程 PID&/li&&li&看源码&/li&&/ol&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&# https://github.com/python/cpython/blob/3.6/Lib/concurrent/futures/process.py#L440
def _adjust_process_count(self):
for _ in range(len(self._processes), self._max_workers):
p = multiprocessing.Process(
target=_process_worker,
args=(self._call_queue,
self._result_queue))
self._processes[p.pid] = p
&/code&&/pre&&/div&&p&从源码得出在主线程创建了管理进程的线程,管理进程的线程创建了 max_workers 个进程(在我的例子里面就只有 3 个 worker).&/p&&blockquote&是个进程池。&/blockquote&&p&好,如果是进程池,似乎 map 过去,除非任务执行完毕或者异常退出,否则进程不销毁。并不能给我们解决 内存泄露 的问题。&/p&&blockquote&等等,如果用多进程池不就好咯?&/blockquote&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&def per_item_calc(item):
df = pd.read.....
# complex calc
return result
result_items = []
step = 300
for idx in range(0,len(all_tobe_calc_items),step):
pieces_tobe_calc_items = all_tobe_calc_items[idx:idx+step]
with ProcessPoolExecutor(3) as pool:
pieces_result_items = pool.map(per_item_calc,pieces_tobe_calc_items)
result_items.append(pieces_result_items)
reduce_results = list(itertools.chain(*result_items))
&/code&&/pre&&/div&&blockquote&当然,这是一种让操作系统帮我 GC 的方法。&b&即 Python 不能帮我 GC 的,操作系统帮我 GC&/b&&br&PS: 其实用 multiprocessing 模块也行,只是线程池可以稍微控制一下进程创建的数量。&/blockquote&&p&总结一下,对于大量的 DataFrame 处理:&/p&&ol&&li&多个进程池是一种处理的方式。&/li&&li&尽量减少 DataFrame 的数量&/li&&li&尽量减少赋值导致的 COPY, 修改时带上 inplace=True&/li&&li&读取 CSV 的时候指定相关列的类型 {‘col_a’: np.float64, ‘col_b’: np.int32},否则 pandas 会产生大量的 object&/li&&/ol&&h2&&b&0xDD 番外篇&/b&&/h2&&p&在分析这次的数据过程中,自己的 Mac 主板也坏掉了,幸好还在保修期,送到苹果店维修了一下。给苹果的售后点个赞。&/p&&h2&&b&0xEE 更新&/b&&/h2&&ul&&li&&b&&/b& 初始化本文&/li&&li&&b&&/b& 增加分析阶段的文字&/li&&li&&b&&/b& 去掉一些 TODO, 发布到我的小站&/li&&li&&b&&/b& 正式发布&/li&&/ul&
0x00 前言机缘巧合,最近公司突然要搞一波大量数据的分析。属于客流类的分析。数据量级也还算不错,经过 gzip 压缩,接近 400 个 点位的 SQL 文件 (MySQL innoDB),大小接近 100GB 左右,原始记录数据估测在 180 亿左右。解压后…… 差不多一个 T 吧。如果…
&p&最近真是新出现了不少增长迅猛的 Python 库啊,在这里推荐 5 个值得在 2018 年关注的库,各个领域精选了 1 个,看看有没有你没听过的?&/p&&p&&br&&/p&&h2&Web 领域:Sanic&/h2&&figure&&img data-rawheight=&463& src=&https://pic2.zhimg.com/v2-e2b1994cbb632e769bdd_b.jpg& data-size=&normal& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic2.zhimg.com/v2-e2b1994cbb632e769bdd_r.jpg&&&/figure&&a href=&//link.zhihu.com/?target=https%3A//github.com/channelcat/sanic& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/v2-b7ae866d4851a7ee0b7d.jpg& data-image-width=&209& data-image-height=&209& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&channelcat/sanic&/a&&p&这个库的名字和之前一个很火的梗有关,有人在 youtube 上画 Sonic 那个蓝色小人,结果一本正经的画出了下面这货,给它起名叫 Sanic,还配了一句话是 Gotta go faster.&/p&&figure&&img data-rawheight=&405& src=&https://pic3.zhimg.com/v2-3f048fdc7a2756bf0bcd3b_b.jpg& data-size=&normal& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic3.zhimg.com/v2-3f048fdc7a2756bf0bcd3b_r.jpg&&&/figure&&p&这个库和 Flask 类似,但是比它快很多,速度能在测试中达到每秒 36000 次请求。在2017年的 Star 增长数几乎是翻了一倍。Gotta go faster!&/p&&p&&br&&/p&&h2&环境与包管理:Pipenv&/h2&&figure&&img data-rawheight=&463& src=&https://pic4.zhimg.com/v2-ca59d0ad1bb6b7e46fd38d7_b.jpg& data-size=&normal& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic4.zhimg.com/v2-ca59d0ad1bb6b7e46fd38d7_r.jpg&&&/figure&&a href=&//link.zhihu.com/?target=https%3A//github.com/pypa/pipenv& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-5bead05ac2ed4.jpg& data-image-width=&374& data-image-height=&374& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&pypa/pipenv&/a&&p&这个库相当于是环境管理和包管理二合一,由 Kenneth Reitz (Requests 的作者 )编写,现在移交给 Python 官方来维护,提供比 pip 体验更好的开发包管理。它的 Slogon 是Python Development Workflow for Humans,用来解决各种环境不一致、安装包的问题。&/p&&p&&br&&/p&&h2&爬虫:Requestium&/h2&&figure&&img data-rawheight=&463& src=&https://pic3.zhimg.com/v2-abd0ab8c17ee2e2d96e742ca_b.jpg& data-size=&normal& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic3.zhimg.com/v2-abd0ab8c17ee2e2d96e742ca_r.jpg&&&/figure&&a href=&//link.zhihu.com/?target=https%3A//github.com/tryolabs/requestium& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-a3813433cbd98eebb77dcc.jpg& data-image-width=&359& data-image-height=&359& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&tryolabs/requestium&/a&&p&现在反爬虫技术越来越厉害,常见的请求 + 解析爬虫随着频率变大和前端开发的复杂化变得并不是那么奏效。Requestium 的好处是,结合了 Chrome 59 以后的 headless 无头特性(代替了 phantomjs)。虽然效率稍微低一点,但是稳,前端渲染的网页也可以爬取解析。是 Requests, Selenium 和 Parsel 的结合体。&/p&&p&&br&&/p&&h2&深度学习:Caffe2&/h2&&figure&&img data-rawheight=&463& src=&https://pic2.zhimg.com/v2-fdefa5c59fb2d_b.jpg& data-size=&normal& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic2.zhimg.com/v2-fdefa5c59fb2d_r.jpg&&&/figure&&a href=&//link.zhihu.com/?target=https%3A//github.com/caffe2/caffe2& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic2.zhimg.com/v2-fedf0a06a8b65e83c3bf8c6a9b59f4c5.jpg& data-image-width=&200& data-image-height=&200& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&caffe2/caffe2&/a&&p&是一个深度学习的库,优势是它是由 Facebook 团队来维护的。可能深度学习方面大家听得最多的是 Tensorflow,但 Caffe2 学习起来更简单轻量,并且它的背景能支持它有一个健壮的发展。&/p&&p&&br&&/p&&h2&文本处理:FlashText&/h2&&figure&&img data-rawheight=&463& src=&https://pic4.zhimg.com/v2-3f0f90484cfe1d4529297_b.jpg& data-size=&normal& data-rawwidth=&720& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic4.zhimg.com/v2-3f0f90484cfe1d4529297_r.jpg&&&/figure&&a href=&//link.zhihu.com/?target=https%3A//github.com/vi3k6i5/flashtext& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-8a51ab5e595f9f.jpg& data-image-width=&200& data-image-height=&200& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vi3k6i5/flashtext&/a&&p&这个库的开发者在 medium 上发了&a href=&//link.zhihu.com/?target=https%3A//medium.freecodecamp.org/regex-was-taking-5-days-flashtext-does-it-in-15-minutes-55ff& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&一篇文章&/a&,标题是:Regex was taking 5 days to run. So I built a tool that did it in 15 minutes. (正则要花5天时间才能完成,所以我做了个工具在15分钟内搞定)。这个库可以快速进行大规模语料库的文本搜索与替换。当关键词数量&500 的时候,FlashText 的搜索速度开始超过正则。&/p&&p&&br&&/p&&p&先写这么多,如果大家喜欢,之后再持续更新这篇精选集。&/p&&hr&&p&如果你看别的 Python 教程看不懂、学不会,那你可以试试 &a href=&//link.zhihu.com/?target=https%3A//www.mugglecode.com/%3Fhmsr%3Dzhihu%26hmpl%3D%26hmcu%3D%26hmkw%3D%26hmci%3D& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&让小白学上瘾的编程入门课-麻瓜编程&/a&&/p&
最近真是新出现了不少增长迅猛的 Python 库啊,在这里推荐 5 个值得在 2018 年关注的库,各个领域精选了 1 个,看看有没有你没听过的? Web 领域:Sanic这个库的名字和之前一个很火的梗有关,有人在 youtube 上画 Sonic 那个蓝色小人,结果…
&p&os的线程分为内核线程和用户线程,内核线程应用程序不能直接碰,这个涉及到os本身的开发&/p&&p&那这个我们不管,反正你写的代码都在jvm上跑,jvm是不会让你直接碰内核线程的&/p&&p&就是说,你在java里面,任何时候启动一个线程,在os看来,都是用户线程&/p&&p&你只能在java里面启动关闭操作用户线程,你不能直接碰内核线程&/p&&p&那当你在java代码里面启动一个线程的时候,jvm有两种选择&/p&&p&1)启动一个os的用户线程,然后你实际的任何操作,都直接对应该用户线程,这就是1:1,这样做之后,调度就由os负责,jvm就不管了,hotspot等主流jvm基本上都是这种做法&/p&&p&2)启动一个虚拟线程,然后执行的时候,交给os上的一个用户线程去执行,这样做的好处就是,jvm可以自己实现调度,而且可以控制虚拟线程的大小,这就是n:m或者1:m,看具体的实现,而如果将线程虚拟化之后,调度就可以由jvm来实现了,想做成1:m还是n:m,完全看jvm调度的实现,这就是协程,绿色线程,名字很多,go其实是这种做法,早期的solaris上的hotspot也是这种做法,后来改了,改成选择1的做法,这样在不同os上hotspot的实现就统一了&/p&&p&好先放这里&/p&&p&那传统的做法,就是启动一个线程池,然后过来一个请求,就从线程池里划拨一个线程去处理那个请求,那这种做法,在并发量比较大的时候,会遇到瓶颈,一个常见的瓶颈就是内存使用,现在的多数jvm,都会启动一个线程予以处理,那一个线程占内存就是1m,hotspot是这样,那这里就有很大的优化空间,尤其是异步可以让io操作转交给内核线程的时候,释放原线程,这就为一个系统用少量线程host住所有请求做好了铺垫&/p&&p&那通过异步改造之后的api,就具备有了通过少量线程host大量请求的条件,所以我们可以将其改造,这是一种方式,先放这里,把另外一种方式先说完&/p&&p&另外一种方式就是,我们还是用线程池的模式,来一个请求就从池子中拿出一个线程予以处理,只是我们把线程换成了协程,这个时候因为是虚拟线程,所以具体占用多少内存,jvm或者go说了算,那go就把协程的内存使用控制在4k,其他的比如kotlin就更少了,所以通过这种方式,我们可以不改变原来机制的前提下,大幅减少内存使用,大大增加了系统的吞吐,这是另外一种方式,quasar用的都是这种方式,这是出路之一,不妨标记为出路零&/p&&p&说回上一种方式,我们用异步改造api,减少线程数之后,虽然也大幅增加了吞吐,但是会遇到新的callback hell的问题,那为了解决这个问题,需要找出路,两条出路&/p&&p&出路一,用fp的高阶函数来做reactive programming,用这种方式来打掉callback hell,这种方式效率最高,这个时候fp就表现出其先进性来,fp的语法搞reactive programming特别自然,反正都是函数,用就是了,都不需要做额外的处理,根本不会遇到callback问题&/p&&p&出路二,找回协程,用协程的suspend/暂停挂起机制,将异步api放入一个协程中去,那这就多了一步,在我们使用异步api之前,我们需要先启动协程,这就是vert.x里面的launch(vertx.dispatcher())这一小段代码做的事,这样做的好处就是,用一层缩进来改造n层嵌套,使得代码可读性加强,但是这有代价,比上一步效率会差大概3%-5%左右&/p&&p&所以一共三种出路,举个例子,比如一个请求用1个线程来处理,那么1个线程的内存使用是1m,还只是stack,那1000个就是1g左右,1000*1m,那我们想增加吞吐,无非两种方式,这里两个变量,要么减少单位线程的内存使用,如果我们选择出路零,那么1m将会变少,变成几k,假设就是4k吧,那就是m,1g的内存我们可以host250*1000个请求,将吞吐增加250倍;如果是出路一,那么我们减少线程,按照vert.x的设计,1c的机器,一般会启动2个eventloop线程,那就是2*1m = 2m,1g内存我们可以host 500*1000个请求,吞吐增加500倍,如果是出路二,线程数还是不变,还是2个eventloop线程,但是有coroutine的开销,kotlin的coroutine非常少,约等于没有,不太容易用一个简答公式精确计算,根据经验判断,会在出路一的基础上下降3-5%,那就算是5%吧,那最终吞吐是host 500*95%*1000 = 475*1000个请求,吞吐增加475倍,这个基本上符合techempower上的测试结果,有兴趣的可以根据这个自行写代码测试&/p&&p&总的来说,出路还是挺多的,以前总被认为是慢慢慢的pure fp,居然在reactive programming上表现出其优越性来,也挺意外的,基本上最后都是几百倍的性能提升,所以对于日常crud的系统来说,还是挺有吸引力的&/p&&p&&/p&
os的线程分为内核线程和用户线程,内核线程应用程序不能直接碰,这个涉及到os本身的开发那这个我们不管,反正你写的代码都在jvm上跑,jvm是不会让你直接碰内核线程的就是说,你在java里面,任何时候启动一个线程,在os看来,都是用户线程你只能在java里面启…
&figure&&img src=&https://pic3.zhimg.com/v2-6bc4ffe4e53b2ddccdd2f23_b.jpg& data-rawwidth=&2560& data-rawheight=&1600& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&https://pic3.zhimg.com/v2-6bc4ffe4e53b2ddccdd2f23_r.jpg&&&/figure&&p&&/p&&blockquote&前言:在现代前端工程中,模块化已经成了前端项目组织文件的标配,网站上线前都会把需要的相关模块预先打包、处理一番。然而打包的方式多种多样,如何才能最优雅的分离业务代码和依赖库、如何才能最高效的利用缓存?本文将会和大家分享饿了么前端团队总结的各方案优劣、踩过的坑,以及最终的解决方案。&/blockquote&&p&众所周知,对于一个站点而言,网站的加载时间一直都是一个很重要的指标。网页加载时间的长短直接影响到了站点的访问量。试想,正在看这篇文章的你,会有多少耐心等待一个网页慢悠悠的打开呢?&/p&&p&对于前端而言,缩短网页加载时间的常见方式有:&/p&&ul&&li&合并文件以减少网络请求数量。&/li&&li&对静态文件设置长达一年的缓存,让浏览器直接从缓存里读取文件。&/li&&/ul&&p&为了让更改过的文件能够生效,我们还会给每个文件的文件名里加上一段根据文件内容计算出的 hash。每当文件内容改变时,这段 hash 也会随之改变,所以浏览器会通过网络下载更新过的文件,但没有更新过的文件仍然会从缓存里读取,从而缩短加载时间。&/p&&p&同理,在开发一个单页面应用的时候,我们通常会将应用的 js 代码打包成两个文件:一个用于存放内容很少更改的第三方依赖库,这部分代码的体积一般会比较大;另一个存放更改比较频繁的业务逻辑代码,但它的体积一般比第三方依赖小。为了方便描述,我们可以分别称这两个文件为 vendor.js 与 app.js。&/p&&p&有了优化方案,接下来就该选择打包工具了。毫无疑问,时下最流行的就是 Webpack 了。Webpack 在文档里提供了一段简单易懂的配置,用于将项目中的 js 代码打包成 vendor.js 与 app.js 这两个文件,并分别在它们的文件名里加上一段根据文件内容生成的 hash,就像前面说的那样:&/p&&div class=&highlight&&&pre&&code class=&language-js&&&span&&/span&&span class=&kr&&const&/span& &span class=&nx&&webpack&/span& &span class=&o&&=&/span& &span class=&nx&&require&/span&&span class=&p&&(&/span&&span class=&s1&&'webpack'&/span&&span class=&p&&)&/span&
&span class=&nx&&module&/span&&span class=&p&&.&/span&&span class=&nx&&exports&/span& &span class=&o&&=&/span& &span class=&p&&{&/span&
&span class=&nx&&entry&/span&&span class=&o&&:&/span& &span class=&p&&{&/span&
&span class=&nx&&vendor&/span&&span class=&o&&:&/span& &span class=&p&&[&/span&&span class=&s1&&'jquery'&/span&&span class=&p&&,&/span& &span class=&s1&&'other-lib'&/span&&span class=&p&&],&/span&
&span class=&nx&&app&/span&&span class=&o&&:&/span& &span class=&s1&&'./entry'&/span&
&span class=&p&&},&/span&
&span class=&nx&&output&/span&&span class=&o&&:&/span& &span class=&p&&{&/span&
&span class=&nx&&filename&/span&&span class=&o&&:&/span& &span class=&s1&&'[name].[chunkhash].js'&/span&
&span class=&p&&},&/span&
&span class=&nx&&plugins&/span&&span class=&o&&:&/span& &span class=&p&&[&/span&
&span class=&k&&new&/span& &span class=&nx&&webpack&/span&&span class=&p&&.&/span&&span class=&nx&&optimize&/span&&span class=&p&&.&/span&&span class=&nx&&CommonsChunkPlugin&/span&&span class=&p&&({&/span&
&span class=&nx&&name&/span&&span class=&o&&:&/span& &span class=&s1&&'vendor'&/span&
&span class=&p&&})&/span&
&span class=&p&&]&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&但是,几乎所有使用类似配置的人都遇到了一个问题:每当更改了业务逻辑代码时,都会导致 vendor.js 的 hash 发生变化。这意味着用户仍然要重新下载 vendor.js,即使这部分代码并没有变过。&/p&&p&为此,开源社区里有人给 Webpack 指出了&a href=&https://link.zhihu.com/?target=https%3A//github.com/webpack/webpack/issues/1315& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&这个问题&/a&,并吸引了很多人一同讨论,一时之间涌出了很多解决的办法,但这些办法既有人说有用,也有人说没用,而官方却迟迟没有给出一个定论。&/p&&p&为了得到一个准确的答案,}

我要回帖

更多关于 下载小象编程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信