SegmentFault 技术也能说人话最新的文章
2020-04-13T00:05:54+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
2021算法岗基础技能树怎么点?
https://segmentfault.com/a/1190000022349966
2020-04-13T00:05:54+08:00
2020-04-13T00:05:54+08:00
这像画码
https://segmentfault.com/u/acstudio
3
<p><img src="/img/bVbFWpV" alt="title.jpg" title="title.jpg"></p>
<p>文章创作于2020年4月,大约7000字,预计阅读时间18分钟,请坐和放宽。</p>
<h2>0 - 前言</h2>
<p>注:本文默认传统算法是所有工程师的基础技能,所以后面提到的算法主要指机器学习以及深度学习等算法。</p>
<p>尽管目前本人求职的重心还是在后端上,但是为了能从现在的人工智能专业硕士顺利毕业,也为了让自己顺便拓展算法工程这条路,简单的规划一下算法这部分需要补的知识和技能还是有必要的。</p>
<p>本文以拿到2021算法岗Offer为目标,从2020的算法岗面经入手,分析需要点的技能树都有哪些。</p>
<h2>1 - 不同算法岗的区别</h2>
<p>首先需要说明的一个地方就是,不同领域的技术岗位,都会按照接触科研和业务的程度来进行一定的区分。</p>
<p>可以简单参考知乎上霍华德在问题<a href="https://link.segmentfault.com/?enc=uYnfE88yFiYwjft0%2FPAK0g%3D%3D.rSmREDiJtYfO0hGYJcKdrszXvE2Wv7JA%2FN6JMAw%2FNaYcH05XDalM1Sdgv%2BLYm8EVJ0hKy1SVn8Ucx77rPxscCg%3D%3D" rel="nofollow">“学术界科研(research)与工业界研发(R&D)有什么区别?”</a>的回答[1],算法岗可以大致分为:</p>
<ul>
<li>业务导向,大部分情况下以Development为主;</li>
<li>技术导向,Research和Development兼顾;</li>
<li>科研导向,大部分情况下会Research为主;</li>
</ul>
<p>近几年这一点在算法岗上表现体现的比较明显,因为在几年前大部分算法都还只在研究阶段,而最近随着一些成熟的机器学习封装库被开放过后,部分行业里开始发现这些算法可以产生实际的价值,所以算法岗位也就呈现了近几年的爆发式增长,尤其是业务导向的算法工程师(因为大部分公司还是希望这些算法能更多更快的产出业务价值)。</p>
<p>当然这话其实说的已经有点晚了,现在已经不是刚开始那样的时候了,那个时候会使用框架、调调参就可以拿到Offer,现在的算法岗更像是浪潮过后的归于正常的情况,不仅需要扎实的理论基础,还需要丰富的项目实践。</p>
<p>我个人是更倾向于业务导向的算法工程,所以本文以这部分为目标来编写,如果你有兴趣了解三种不同岗位的细节,可以阅读夕小瑶的一篇公众号文章<a href="https://link.segmentfault.com/?enc=kwFkdccbMOfZ60cuOPqG%2Bg%3D%3D.uR6V0tBEWClcKazhsWQDM0EQuJbDMzF2n2FgfiPR9x0%3D" rel="nofollow">《拒绝跟风,谈谈几种算法岗的区别和体验》</a>[2]。</p>
<h2>2 - 2020面经读后感</h2>
<p>为了更好地了解各行业公司都比较看重哪些方面的东西(很可能也都是这些公司在用的技术),我选择直接从算法岗的面经里去寻找可能的答案,面经贴主要是<a href="https://link.segmentfault.com/?enc=Ck6N9HG0yo%2B5czzQlpQ2FA%3D%3D.mzfPq%2Bhow9DLMflbtUoJONdQgKVGAC3Ii0h7KWicJu%2Bug34qsvj9WwI7AppJ6fVo7LL%2BdUoMS7gzcER4aom6sg%3D%3D" rel="nofollow">牛客网</a>上的[3]。</p>
<p>找到的点可以简单分为以下几类:</p>
<ul>
<li>纯数学相关</li>
<li>机器学习</li>
<li>深度学习</li>
<li>NLP相关</li>
<li>推荐算法</li>
</ul>
<p>一些传统算法相关就不在此列了(Leetcode和一些书比如《剑指Offer》整理的也足够多了)。我能够看到的面经是有限的,面经里提供的内容也是有限的,所以后面的内容不能说能概括到全部,但是至少能提取出很大一部分频繁出现的关键词(如果真的有需要的话再写个爬虫+关键词提取吧)。</p>
<p>内容因为并没有特别多的先后依赖关系,所以就按照在面经里出现的顺序来列了。</p>
<h3>2.1 - 纯数学相关</h3>
<ul>
<li>事件概率计算</li>
<li>狄利克雷分布</li>
<li>最大似然估计和贝叶斯估计</li>
<li>...</li>
</ul>
<h3>2.2 - 机器学习</h3>
<ul>
<li>数据清洗、数据平滑</li>
<li>常用的降维方式、PCA</li>
<li>LDA(Linear Discriminant Analysis)</li>
<li>决策树,ID3、C4.5、CART</li>
<li>XGBoost、LightGBM、随机森林、Adaboost、GBDT</li>
<li>SVM原理、对偶问题</li>
<li>L1、L2正则化</li>
<li>过拟合</li>
<li>特征选择方法</li>
<li>LR(Logistic Regression)和SVM、Linear SVM 和 LR</li>
<li>聚类方法、K-means、层次聚类</li>
<li>模型的评价指标、ROC</li>
<li>朴素贝叶斯原理</li>
<li>scikit-learn、numpy</li>
<li>bagging和boosting</li>
<li>集成学习</li>
<li>分类方法</li>
<li>模型上线优化</li>
<li>连续值、离散值,离散化连续特征的好处</li>
<li>回归方法、线性回归、岭回归、Lasso回归、LR</li>
<li>信息增益,信息增益比,Gini系数的关系</li>
<li>One-Hot编码的原理及意义</li>
<li>Optimizers(Gradient Descent、...)</li>
<li>统计学习算法</li>
<li>...</li>
</ul>
<h3>2.3 - 深度学习</h3>
<ul>
<li>Feedforward Neural Network</li>
<li>Back Propagation</li>
<li>Layers,convolutional、pooling、full connected</li>
<li>CNN(卷积)、RNN(梯度消失问题)、LSTM、GRU</li>
<li>GAN</li>
<li>目标检测,R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD、...</li>
<li>SoftMax、Sigmoid</li>
<li>Embedding</li>
<li>注意力机制</li>
<li>GCN(Graph Convolutional Network)</li>
<li>Optimizers(Gradient Descent、BGD、SGD、Adam、Adagard...)</li>
<li>Tensorflow、Keras、PyTorch</li>
<li>Activation(sigmoid、softmax、relu...)</li>
<li>MobileNet</li>
<li>Dropout</li>
<li>CPU、GPU加速</li>
<li>...</li>
</ul>
<h3>2.4 - NLP相关</h3>
<ul>
<li>关键字提取、TF-IDF</li>
<li>命名实体</li>
<li>LDA(Latent Dirichlet Allocation)</li>
<li>word2vec</li>
<li>Bert、Transformer</li>
<li>...</li>
</ul>
<h3>2.5 - 推荐算法</h3>
<ul>
<li>基于内容的推荐</li>
<li>协同过滤推荐、UserCF、ItemCF</li>
<li>如何处理稀疏矩阵</li>
<li>...</li>
</ul>
<h3>2.6 - 面经总结</h3>
<p>在大部分算法面试中,面试官的问题都是围绕着简历上的项目来问的,我们可以看到上面的很多项目所涉及到的点,面试官都有可能往深了问,比如:</p>
<ul>
<li>SVM原始问题为什么要转化为对偶问题,为什么对偶问题就好求解,原始问题不能求解么?</li>
<li>K-means 中我想聚成100类 结果发现只能聚成98类,为什么?</li>
<li>LR和SVM这两个应用起来有什么不同?</li>
<li>对于PCA,会有第一主成分、第二主成分,怎么为什么第一主成分是第一,原因是什么?</li>
<li>bagging 和boosting 哪个可以让结果的方差更小一些,为什么?</li>
<li>...</li>
</ul>
<p>所以在学习过程中不光要知道How,还是要多知道几个Why,一是为了能在面试的时候能回答出问题,二是为了更好地理解手里的这个工具。</p>
<h2>3 - 算法的基础技能树</h2>
<p>面经总结出来的点也还是有点乱,所以我又参考了一些算法学习路线的帖子来简单的归类梳理一下各个点,主要是参考的机器之心的这篇<a href="https://link.segmentfault.com/?enc=%2FhcCMsMK%2BbdZMMpOR8MVGQ%3D%3D.NDAGsVmV%2BuYOfEjDvwHveuBkJHMgtPYoP9Iaioou5wM8CFZGBoqtDxZQOSAQg%2B0z6xXwrKIeJI5GbSjovq62kw%3D%3D" rel="nofollow">完备的 AI 学习路线,最详细的中英文资源整理</a>[4],时效为2019-04-28,还参考了一个不知道我什么时候在哪里找到的知识点总结图,如果有人知道出处的话可以在评论里和我说一下,图片链接会附在文章末尾(图片很大,所以放进来会看不清)。</p>
<h3>3.1 - 数学基础</h3>
<ul>
<li>高等数学</li>
<li>线性代数</li>
<li>概率论与数理统计</li>
</ul>
<p>并不是说要把上面三个教材吃的完全透了才开始学习后面的,其实人工智能领域很多方法都只是用到了其中的一小部分,有一些专门总结了的机器学习中需要使用到的数学知识的书籍和文档[4],你可以在机器之心的公众号文章找到这些(我在文章末尾也会上一个链接),具有基本的数学基础的可以用来复习,没有数学基础的还是建议在看不懂的地方回顾到教材。</p>
<p>有些帖子可能会在数学基础这部分加上一个凸优化,个人理解上,在纯粹的学习过程中凸优化可以说是最枯燥的一门课,里面大部分是一些凸优化的定义和理论公式的证明,所以建议在后期遇到的时候再切入某一个点深入学习。</p>
<h3>3.2 - 编程基础</h3>
<p>在数值分析和人工智能这方面,还是Python支持的库比较方便,在入门学习方面已经足够使用了,版本目前推荐3.5 or 3.6。</p>
<p>Anaconda(or Miniconda)是一个比较方便的Python虚拟环境和包管理软件,但是在某些时候会遇到麻烦事(比如一些算法框架的奇奇怪怪的环境要求),但是在大部分情况下的入门阶段已经足够使用了。</p>
<p>Python的IDE大部分人常用的就是Pycharm,如果有些能力折腾的,可以考虑用vscode+插件等等。</p>
<h3>3.3 - 数据处理/分析/挖掘</h3>
<p>实际使用中,很多机器学习、深度学习方法只有在高质量数据中才能起作用,比如数据的信息量足够多、噪声和错误信息足够少。而实际数据收集过程中,很多情况下不可能让数据这么完美,所以需要进行一些初步的数据处理(采集、清洗、采样、去噪、降维、...)。</p>
<p>除了Python语言基础,还需要掌握一些基础的数据处理库,比如numpy、pandas、matplotlib等,可以参考机器之心推荐的《利用python进行数据分析》。</p>
<blockquote>这本书含有大量的实践案例,你将学会如何利用各种Python库(包括NumPy,Pandas、Matplotlib以及IPython等)高效地解决各式各样的数据分析问题。如果把代码都运行一次,基本上就能解决数据分析的大部分问题了。</blockquote>
<p>另外还有就是[4]:</p>
<ul>
<li><a href="https://link.segmentfault.com/?enc=ia9Zh5aHVXvUNhaMFmmf8g%3D%3D.L1cYPT7c6FPRJ94dodd4mkwH51NYMk2mY07DxvMPvLtZMIWc4nHkSruUUQhWHIUiCPEDriS5sk%2BC%2FhbhvYoMpw%3D%3D" rel="nofollow">数据挖掘中的特征工程</a></li>
<li><a href="https://link.segmentfault.com/?enc=5bhOzpmTN0dJXXk1jsP4tQ%3D%3D.Yvy4WJfN7HOzmJm32xldL%2FatKzRHD%2B4S1VEP%2FnGf4IEu%2FCplUhcBlzId1SACvSgWL%2BMSfIPZ7AABxKpqwP3i9w%3D%3D" rel="nofollow">一些数据挖掘的项目</a></li>
</ul>
<p>数据挖掘可以帮助我们初步的理解数据各特征之间具有的一些关系,增加或者删除一些特征来帮助后续的学习。数据挖掘可以通过一些导论书籍或者课程进行一些初步系统性的了解,其中的大部分原理都不是很高深。</p>
<h3>3.4 - 传统机器学习</h3>
<h4>3.4.1 - 入门</h4>
<p>如果在入门的时候,一开始就学习数学和理论公式,也不去弄明白这个东西到底有什么用,就很难去理解到底为什么需要这些理论。</p>
<p>在学习每个机器学习算法前,可以先笼统的明白这个东西的作用,然后带着问题“这个是怎么实现的?”去探究算法的理论,才能比较贯通的理解其中的数学和公式。</p>
<p>这里推荐一个网站,<a href="https://link.segmentfault.com/?enc=LqMdAqOiynRjLzvipr%2FY%2Fw%3D%3D.6cjRqhEbUpw1zjbeSeaq%2B69lEEUtnDgk8K2noKT42wM%3D" rel="nofollow">产品经理的人工智能学习库</a>。</p>
<blockquote>人工智能领域的百科全书,非常适合小白和新手入门 AI 领域。现在市面上大家看到的绝大部分 AI 资料都是追求严谨的“理工科天书”,这个世界不缺少严谨真确晦涩难懂的 AI 资料,但是很缺容易理解的内容。我们希望抛开复杂的公式,复杂的逻辑,复杂的专用名词。做一套文科生也能看懂的 AI 知识库。</blockquote>
<h4>3.4.2 - 理论</h4>
<p>机器学习的理论部分大概有:</p>
<ul>
<li>
<p>机器学习所面向的问题</p>
<ul>
<li>
<p>分类</p>
<ul>
<li>决策树</li>
<li>K-近邻</li>
<li>SVM</li>
<li>Logistic回归</li>
<li>贝叶斯</li>
<li>随机森林</li>
<li>...</li>
</ul>
</li>
<li>
<p>回归</p>
<ul>
<li>线性回归</li>
<li>最小二乘回归</li>
<li>局部回归</li>
<li>神经网络</li>
<li>...</li>
</ul>
</li>
<li>
<p>聚类</p>
<ul>
<li>K-means</li>
<li>EM</li>
<li>...</li>
</ul>
</li>
<li>
<p>降维</p>
<ul>
<li>主成分分析 PCA</li>
<li>线性判别分析 LDA</li>
<li>...</li>
</ul>
</li>
<li>...</li>
</ul>
</li>
<li>
<p>回归</p>
<ul>
<li>线性回归</li>
<li>Logistic回归</li>
<li>...</li>
</ul>
</li>
<li>
<p>决策树与随机森林</p>
<ul>
<li>ID3</li>
<li>C4.5</li>
<li>CART</li>
<li>回归树</li>
<li>随机森林</li>
<li>...</li>
</ul>
</li>
<li>
<p>SVM</p>
<ul>
<li>线性可分</li>
<li>线性不可分</li>
</ul>
</li>
<li>最大熵与EM算法</li>
<li>
<p>多算法组合与模型优化</p>
<ul>
<li>模型选择</li>
<li>模型状态分析</li>
<li>模型优化</li>
<li>模型融合</li>
</ul>
</li>
<li>贝叶斯网络</li>
<li>
<p>隐马尔可夫链HMM</p>
<ul>
<li>马尔可夫链</li>
<li>隐马尔可夫链</li>
</ul>
</li>
<li>主题模型LDA</li>
<li>集成学习</li>
<li>...</li>
</ul>
<p>内心OS:这总结下来基本上和某些书的目录差不多了。</p>
<p>推荐课程[4]:</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=k29kpPXUAxdxhlA9ioJpRw%3D%3D.4skT%2F4zoWXJGb7J3qw5YF%2FiPbqMqr1KAGE8u7MFwXqfBAjx4ZX2GpM%2FksctVRE1v" rel="nofollow">《Machine Learning》- 吴恩达,源:Coursera</a>,比较适合入门的课程。</li>
<li>
<a href="https://link.segmentfault.com/?enc=Eyxbet7HcbHZlRilckfL2w%3D%3D.4JhleNJIEX9c%2BP4VIfVUWw4cuZywONhFJBM8NWM26Xgi1%2BuvbXxKqOHxIxNiqyDNNUG5OEmqSbNvOQwAma595%2BaAqOyov6ndaBjfpR7DD%2FlpoihvzJ9XBf5uB6ASs6D5tteooU%2B60v4O5RINIfJNaoT6TLxApF1OA8pddPfytgw%3D" rel="nofollow">《机器学习》- 吴恩达,源:网易云课堂</a>,网易云课堂对上面课程的翻译和搬运。</li>
<li>
<a href="https://link.segmentfault.com/?enc=7KvEdpDyM%2FEwHNgI5oq07w%3D%3D.3n31eXyTcgKNBpAvv3Evsv8o6YV7Hra2SPmFfdUKflGMLf3BWTRs%2BW39l8mAoJHdsOtxT%2BDEi2dj2T%2FFL7nMNg%3D%3D" rel="nofollow">《CS229》 - 吴恩达,斯坦福,源:网易云</a>,与《Machine Learning》相似,有更多的数学要求和公式的推导。</li>
<li>
<a href="https://www.bilibili.com/video/av36731342">《机器学习基石》 - 林轩田,台湾大学,源:Bilibili</a>,老师风趣幽默,侧重于机器学习理论知识,配套书籍<a href="https://link.segmentfault.com/?enc=jQvcFZILSrECZiJJYl6hDQ%3D%3D.w%2FiLID6JjQ%2BxAjhhImOJ%2BJGiqIjFAI1xzLrkgPUt7T8%3D" rel="nofollow">《Learning From Data》</a>。</li>
</ul>
<p>推荐书籍[4]:</p>
<ul>
<li>西瓜书《机器学习》- 周志华,主要是机器学习的核心数学理论和算法。</li>
<li>《统计学习方法》- 李航,更加完备和专业的机器学习理论知识,作为夯实理论非常不错。</li>
<li>《Pattern Recognition and Machine Learning》,中文译名《模式识别与机器学习》,简称PRML,出自微软剑桥研究院实验室主任 克里斯托弗·毕晓普(Christopher Bishop)之手,豆瓣评分9.5,目前这本书已经被微软开源,地址:<a href="https://link.segmentfault.com/?enc=6bqsY9Gg%2BDPHZXyuT97qqg%3D%3D.YD%2F5fId%2FO101LgX2KDdrfuTNyUAZJG69cpg2j88f7bsZA1Ko3byfkVp3iSbmeQa3GejrVoIiXi2udYcWO08bdzn9BfV%2Fmhhqgn6IQmMcqjVU8rdRkdwXQfO3iZt5Iqz%2F9mV28V98W44oFmuXgz3e3zK%2FN5QB427f465hXbvajdA%3D" rel="nofollow">https://www.microsoft.com/en-...</a>,书是英文的,网上可以找到一些第三方的中文翻译,不过还是建议读英文,再次也是中英对照着来。</li>
</ul>
<h4>3.4.3 - 实践</h4>
<p>在初步入门和学习理论后,为了活学活用学到的算法,可以尝试进行实践。</p>
<p>首先是一些可以拓展能力的常用工具(免得自己造轮子):</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=wjY9yWOn3kWsZ45zWLWidA%3D%3D.92Mi%2BnmyzVRKX7rdfIbD3RpQjtMYYUPriDAx5fmGp45mQU6ULocOs37%2Fg2hwzHku" rel="nofollow">scikit-learn</a>:一个Python第三方提供的非常强力的机器学习库,它包含了从数据预处理到训练模型的各个方面。在实战使用scikit-learn中可以极大的节省我们编写代码的时间以及减少我们的代码量,使我们有更多的精力去分析数据分布,调整模型和修改超参。</li>
<li>
<a href="https://link.segmentfault.com/?enc=efhiSOiqyXMebZUGwX52vw%3D%3D.8WHxpkgIDOJYzfa%2BkRAcr0LlwYOLGo5kkS4m3MAnVow%3D" rel="nofollow">XGBoost</a>:xgboost是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包,比常见的工具包快10倍以上。在数据科学方面,有大量kaggle选手选用它进行数据挖掘比赛,其中包括两个以上kaggle比赛的夺冠方案。在工业界规模方面,xgboost的分布式版本有广泛的可移植性,支持在YARN, MPI, Sungrid Engine等各个平台上面运行,并且保留了单机并行版本的各种优化,使得它可以很好地解决于工业界规模的问题。</li>
<li>
<a href="https://link.segmentfault.com/?enc=Ag3mknYg25SLo5cVBOPIiw%3D%3D.03kYlTN2LEWikAEXk9MeS2mK6CwpiFfyR29FXmcXNc8UuB8KjKHyTRE9fPt6TyUy" rel="nofollow">LightBGM</a>: LightGBM(Light Gradient Boosting Machine)同样是一款基于决策树算法的分布式梯度提升框架。为了满足工业界缩短模型计算时间的需求,LightGBM的设计思路主要是两点:1. 减小数据对内存的使用,保证单个机器在不牺牲速度的情况下,尽可能地用上更多的数据;2. 减小通信的代价,提升多机并行时的效率,实现在计算上的线性加速。由此可见,LightGBM的设计初衷就是提供一个快速高效、低内存占用、高准确度、支持并行和大规模数据处理的数据科学工具。</li>
<li>...</li>
</ul>
<p>然后就可以去<a href="https://link.segmentfault.com/?enc=Apr5Yfh90dCrk3wclezHwA%3D%3D.Qtpvz%2B8ymlIl1dwU8o1XJoDuxs0fzQDjNW78qi8dWAo%3D" rel="nofollow">Kaggle</a>上和大佬们对线了,如果你有能力也有idea,可以自己开出一个项目来做。</p>
<p>如果你对某些算法有更深程度的理解,你甚至可以尝试用自己代码复现这些算法。</p>
<p>推荐书籍:</p>
<ul><li>《Scikit-Learn 与 TensorFlow 机器学习使用指南》:这本书分为两大部分,第一部分介绍机器学习基础算法,每章都配备 Scikit-Learn 实操项目;第二部分介绍神经网络与深度学习,每章配备 TensorFlow 实操项目。如果只是机器学习,可先看第一部分的内容。</li></ul>
<h3>3.5 - 深度学习</h3>
<h4>3.5.1 - 入门</h4>
<p>在这里同样推荐<a href="https://link.segmentfault.com/?enc=3fRZdlptndhEL%2Bf7W6fRoA%3D%3D.Bw0bEwWib62A1Iim3LtPWUBfLmpsmYzZ74qus%2FyvG%2Bg%3D" rel="nofollow">产品经理的人工智能学习库</a>。</p>
<h4>3.5.2 - 理论</h4>
<p>深度学习的理论部分大概有[4]:</p>
<ul>
<li>
<p>基础神经网络</p>
<ul>
<li>神经元</li>
<li>激活函数</li>
<li>基本结构:输入层、隐藏层、输出层</li>
<li>反向传播算法</li>
</ul>
</li>
<li>
<p>CNN</p>
<ul>
<li>卷积层</li>
<li>池化层</li>
<li>全连接层</li>
<li>CNN的典型网络结构(LeNet, AlexNet, VGG, ResNet, ...)</li>
</ul>
</li>
<li>
<p>RNN</p>
<ul>
<li>单向RNN</li>
<li>双向RNN</li>
<li>深度RNN</li>
<li>LSTM</li>
<li>GRU</li>
</ul>
</li>
<li>GAN</li>
<li>...</li>
</ul>
<p>你可以从广度上入手,在都了解的基础上,选择一个方向进行深入学习:</p>
<ul>
<li>计算机视觉(图像、视频处理,主要用CNN);</li>
<li>自然语言处理NLP(包括文本、语音处理,序列数据往往需要RNN);</li>
<li>生成模型(GAN、VAE等等);</li>
</ul>
<p>推荐课程[4]:</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=K2OfNRv9t92jkjhEE%2Fpc3w%3D%3D.JrrI5YI8VCR7ycMNcGY0O9i0QN75eI5Shw1JQIUftMAco%2BFfAmBz7Oj0oqWWkTGWK0KvoRWZSZWmmMRLv5dGDg%3D%3D" rel="nofollow">《Deep Learning》- 吴恩达,源:网易云</a>,整个专题共包括五门课程:01.神经网络和深度学习;02.改善深层神经网络-超参数调试、正则化以及优化;03.结构化机器学习项目;04.卷积神经网络;05.序列模型。</li>
<li>
<a href="https://www.bilibili.com/video/av18904696?from=search&seid=10813837536595120136">程序员深度学习实战 - Fast.ai,源:Bilibili</a>,与吴恩达《Deep Learning》并驾齐驱,这门课最大的特点便是“自上而下”而不是“自下而上”,是绝佳的通过实战学习深度学习的课程,<a href="https://link.segmentfault.com/?enc=XqBlLNN1kbE%2BL96DNzq4Qg%3D%3D.CBjoKi9PRLh2J016mAVvZ%2FNK8%2BJ3xsQt5gGqI869repOAuDj5K4VyQZl3iZnjEBQ" rel="nofollow">中文字母,源CSDN</a>。</li>
<li>
<a href="https://www.bilibili.com/video/av47055599">CS230 - 吴恩达,斯坦福,源Bilibili</a>,涵盖了CNNs, RNNs, LSTM, Adam, Dropout, BatchNorm, Xavier/He initialization 等深度学习的基本模型,涉及医疗、自动驾驶、手语识别、音乐生成和自然语言处理等领域。</li>
</ul>
<p>推荐书籍[4]:</p>
<ul>
<li>开源书籍<a href="https://link.segmentfault.com/?enc=CxaOjbDIlFFGDU%2FL8qz%2FAg%3D%3D.3cHqvpInMXN8UQblsXg0DCoADWdSXpMRr5U7DSpYlMQ%3D" rel="nofollow">《神经网络与深度学习》 - 复旦邱锡鹏</a>,这本书花费了邱老师三年的时间,将自己的研究,日常的教学和实践结合梳理出这个深度学习知识体系。该书主要介绍神经网络与深度学习中的基础知识、主要模型(前馈网络、卷积网络、循环网络等)以及在计算机视觉、自然语言处理等领域的应用[5]。</li>
<li>花书<a href="https://link.segmentfault.com/?enc=Chc0475ruRdbwl4WA81ACQ%3D%3D.T4tGifpZlSZ3Ul95N8aZqAbrscvt9PZdCvBwYOakBjcqQ%2FSbtdc5p9F%2Blp8HcFLtSB7ZQVzrXOPj6gw2wK13%2Fg%3D%3D" rel="nofollow">《深度学习》,源:Github网友翻译</a>,该书从浅入深介绍了基础数学知识、机器学习经验以及现阶段深度学习的理论和发展,它能帮助人工智能技术爱好者和从业人员在三位专家学者的思维带领下全方位了解深度学习。</li>
<li>神贴<a href="https://link.segmentfault.com/?enc=q4EoKcKorRQsHtt%2F9uUBfw%3D%3D.7tuvH6lh6QWqkXOLS%2B5%2BzhzQ%2F7X3m5PDHo2KKWQ2rIZ5iJtEnQSWqi%2FRq4aKOE4htGN5IC0ldOUP2n9tjZ%2F0qA%3D%3D" rel="nofollow">《深度学习 500 问》</a>,作者是川大的一名优秀毕业生谈继勇。该项目以深度学习面试问答形式,收集了 500 个问题和答案。内容涉及了常用的概率知识、线性代数、机器学习、深度学习、计算机视觉等热点问题,该书目前尚未完结,却已经收获了Github 2.4w stars(现在已经3.7w star了)。</li>
</ul>
<h4>3.5.3 - 实践</h4>
<p>在初步入门和学习理论后,为了活学活用学到的深度学习算法,可以尝试进行实践。</p>
<p>首先是一些可以拓展能力的常用工具(免得自己造轮子):</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=hPjmXI6JFg%2BVlmfGbyvZjg%3D%3D.z%2FOU86SP5%2BY0xfUDb2242OZvY%2BQ4l2qzlmca2gSdhHk%3D" rel="nofollow">TensorFlow</a>,Google开源的深度学习框架,不过接口都比较底层,可能入门级稍难。</li>
<li>
<a href="https://link.segmentfault.com/?enc=zgH8IAgld%2BhvC78s1ncNiw%3D%3D.XngwnvzVsLbWmZ7%2BQ9PddejX8cFkCliWLB5t04YEedk%3D" rel="nofollow">Keras</a>,一个用 Python 编写的高级神经网络 API,它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行。Keras对入门友好,不过其中过多的封装可能会导致需要自定义修改比较麻烦,所以他们主要面向的是快速实验、快速验证的任务。</li>
<li>
<a href="https://link.segmentfault.com/?enc=X5vPm4L8EbsBUq1MK07Ifw%3D%3D.J3r8xTB2kyu5zNVqsYb7aAzK65Ujb9ZN43H%2FWkEeUDM%3D" rel="nofollow">PyTorch</a>,Facebook发布的一套深度学习框架,PyTorch专注于直接处理数组表达式的较低级别 API。去年它受到了大量关注,成为学术研究和需要优化自定义表达式的深度学习应用偏好的解决方案。</li>
</ul>
<p>关于哪个工具更好的问题,"支持者"之间也是争议不断,其实也不用纠结到底应该选哪一个,都试试不就知道了(逃。</p>
<p>选择一个工具学会后,就可以去<a href="https://link.segmentfault.com/?enc=y7il7NpoxVVDUb6c5VPW%2FQ%3D%3D.FwLVHgeBhFIoRiuzNXjovDMQ8MjXgh5JVC3sWzrjfls%3D" rel="nofollow">Kaggle</a>上和大佬们对线了,如果你有能力也有idea,可以自己开出一个项目来做。</p>
<h3>3.6 - 其他</h3>
<p>至于强化学习、迁移学习、计算机视觉、NLP、推荐系统、知识图谱等内容,限于文章篇幅,就不在这里介绍了,不过你可以在机器之心的那篇文章中找到和他们有关的内容。</p>
<h3>3.7 - 论文阅读</h3>
<p>机器学习、深度学习大部分理论内容都来自计算机科研领域发表的论文,当下的前沿技术也都在近几年发表的论文中。</p>
<p>作为入门、理论、实践的之后一个拓展阶段,可以通过阅读前沿论文来增加知识面。</p>
<p>由于前沿论文阅读并不能算是一个业务导向的算法工程师所必须具有的能力,所以在这就不做过多的介绍了,同样,你可以在机器之心的那篇文章中找到关于阅读前沿Paper的相关介绍。</p>
<h2>4 - 总结</h2>
<p>不久前,某404网站给我推送了一个视频,名字看起来非常标题党,<a href="https://link.segmentfault.com/?enc=DDGVuJrQXgFpSDlfdPOhtg%3D%3D.XdjBYbFUH4HlSpp9K2UO5JPfiLP0Sm7OPOC07G6voByGvszPq90g2bVficCw4XUpoZRoKQXh1FhfAATznoFgoA%3D%3D" rel="nofollow">Don't learn machine learning - Daniel Bourke,源:Youtube</a>,其中作者核心的内容是不要为了只是学习算法而学习算法,要为了创造产品(或者说应用、或者说解决问题)而学习算法,有条件的同学可以看看(暂时还没有看到国内的翻译搬运,如果有时间有机会的话我就翻译搬运一下吧)。</p>
<p>面向Offer学习未必是最优的一条路。我的目标是以后端为主线发展,之所以还没有完全的放弃这部分的算法,一部分是因为我的专业,更多的原因是我知道在某些问题上只有这些算法才能有效地解决,会用更多的算法也可以让程序员解决更多的问题。</p>
<h2>5 - 参考文章</h2>
<ul>
<li>[1] 学术界科研(research)与工业界研发(R&D)有什么区别?, <a href="https://link.segmentfault.com/?enc=25aKkbEvZ8evVxecHymDqw%3D%3D.5FZtNIDMDDyzkgRIF%2FSj8dGJnf%2FcAL6tDZdlQ9FRCLKu2BTG50WLmj7fgBxqDdTF9uw8enDtyhDyRjrnjTko8w%3D%3D" rel="nofollow">https://www.zhihu.com/questio...</a>
</li>
<li>[2] 拒绝跟风,谈谈几种算法岗的区别和体验 - 夕小瑶, <a href="https://link.segmentfault.com/?enc=2xNZs83KdFBCyWsyb0fbsg%3D%3D.z%2FFiaf7Jw6FrqUA8LkjIbntO9yd%2FeEhcH29GIQh7K2Q%3D" rel="nofollow">http://suo.im/6385SY</a>
</li>
<li>[3] 算法工程师精选面经合集 - 牛客网, <a href="https://link.segmentfault.com/?enc=lWkhh8hcJ8rpTTFtd1Il%2BQ%3D%3D.NzcSqeYRoLH%2Bp8y4R0PeVyeNeeNxT%2ByoGjtBFnHMtBuNG6tLfFL44Edyd87c6D0ZaFnGi3noxE7dVOGF%2BaBeFw%3D%3D" rel="nofollow">https://www.nowcoder.com/disc...</a>
</li>
<li>[4] 完备的 AI 学习路线,最详细的中英文资源整理 - 机器之心, <a href="https://link.segmentfault.com/?enc=bsluLPUUKV%2Bg0l4grXt24w%3D%3D.RU79HyjRR%2F7wXvAHn6h5uDXBsJAZU7OwF9DC7LTrCoxBLRJYh9%2FQ8tYHB3SugHaDhVVkoLo4uPbMa3B1%2FoGk4A%3D%3D" rel="nofollow">https://mp.weixin.qq.com/s/dI...</a>
</li>
<li>[5] 复旦教授邱锡鹏开源发布《神经网络与深度学习》- Datawhale, <a href="https://link.segmentfault.com/?enc=J30nDRJAvniQbeAy8%2Fzopw%3D%3D.ysxWcXeKrHFD8p%2F%2FW4HpltX%2FN20zRbME%2BWV7%2FowItCY%3D" rel="nofollow">http://suo.im/6qyB8b</a>
</li>
</ul>
为什么要用Go语言?
https://segmentfault.com/a/1190000022285902
2020-04-07T12:52:41+08:00
2020-04-07T12:52:41+08:00
这像画码
https://segmentfault.com/u/acstudio
23
<p>本文章创作于2020年4月,大约6000字,预计阅读时间15分钟,请坐和放宽。</p>
<p><img src="/img/bVbFFJV" alt="logo.png" title="logo.png"></p>
<h2>前言</h2>
<blockquote>Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易[1]。<p>Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了[1]。</p>
</blockquote>
<p>其实早在2018年前,我就已经有在国内的程序员环境中断断续续地听到Go语言的消息,Go语言提供的方便的并发编程方式,十分适合我当时选择的毕业设计选题,但是受限于导师的语言选择、项目的进度追赶、考研的时间压榨,一直没有机会来好好地学习这门语言。</p>
<p>在进入研究生阶段后,尽管研究的方向和算法相关,但未来的职业方向还是选择了以后端为主,主要是因为想做更多和业务相关的工作。为了能在有限的时间里给予自己足够深的知识底蕴,选择了一些让自己去深入了解的方向,Go语言自然也在其中,今天终于有机会来开始研究这门语言。</p>
<h2>为什么要用Go语言?</h2>
<p>撰写此文的初衷,是本文的标题,也是我作为初学者一直以来的疑问:</p>
<p><strong>“我为什么要用Go语言?”</strong></p>
<p>为了回答这个问题,我翻阅了很多Go语言相关的文档、书籍和教程,<strong>我发现我很难在它们之中找到非常明显直接的答案</strong>,书上和教程只会说,<strong>“是的,Go语言好用”</strong>。</p>
<p>对于部分人来说,这个问题的答案或许很“明显”,比如选择Go语言是因为Google设计的语言、Go开发赚的钱多、XX公司使用Go语言等等,如果想要了解这门语言更加本质的东西,仅仅这些答案我认为是还不够的。</p>
<p>部分Go的教徒可能会说,<strong>他们选择的理由是和语言本身相关的</strong>,比如:</p>
<ul>
<li><strong>Go编译快</strong></li>
<li><strong>Go执行快</strong></li>
<li><strong>Go并发编程方便</strong></li>
<li><strong>Go有垃圾回收(Garbage Collection, GC)</strong></li>
</ul>
<p>的确,Go是有这些特点,<strong>但这并非都是Go独有的</strong>:</p>
<ul>
<li>运行时解释的脚本语言(比如Python)几乎不需要时间编译</li>
<li>C、C++甚至是汇编,基本上能够榨干一台机器的大部分性能</li>
<li>大部分语言都有并发编程的支持库</li>
<li>大部分语言都不需要程序员主动关注内存情况</li>
</ul>
<p>一些Go的忠实粉丝把这种<strong>All in One</strong>的特性作为评价语言的标准,他们认为至少在这些方面,Go是可以完美的代替其他语言的。</p>
<p><strong>那么,Go真的能优秀到完全替代另一个语言么?</strong></p>
<p>其实未必,我始终认为银弹是不存在的[2],无论是在这次调查前,还是在这次调查后。</p>
<p>本文从Go语言被设计的初衷出发,深入互联网各种角落,调查Go所具有的那些特性是否足够优秀,同时和其他语言进行适当的比较,你可以选择性的阅读、接受或者反对我的内容,毕竟有交流才能传播知识。</p>
<p><strong>我的最终目的是让更多的初学者看到Go没有轻易暴露出的缺点,同时也能看到Go真正优秀的地方</strong>。</p>
<h3>设计Go的初衷</h3>
<blockquote>Go语言的主要目标是将静态语言的安全性和高效性与动态语言的易开发性进行有机结合,达到完美平衡,从而使编程变得更加有乐趣,而不是在艰难抉择中痛苦前行[3]。</blockquote>
<p>Google公司不可能无缘无故地设计一个新语言(一些特性相比于其他语言也没有新到哪里去),这一切肯定是有原因的。</p>
<p>设计Go语言是为了解决当时Google开发遇到的一些问题[4]:</p>
<ul>
<li>C++编译慢、没有现代化(入门级友好的)的内存管理</li>
<li>数以万计行的代码,难以维护</li>
<li>部署的平台各式各样,交叉编译困难</li>
<li>......</li>
</ul>
<p><img src="/img/bVbFFJW" alt="joke.png" title="joke.png"></p>
<p><strong>找不到什么合适的语言,想着反正都是弄来自己用,Google选择造个轮子试试。</strong></p>
<blockquote>Go 语言起源 2007 年,并于 2009 年正式对外发布。它从 2009 年 9 月 21 日开始作为谷歌公司 20%兼职项目,即相关员工利用 20% 的空余时间来参与 Go 语言的研发工作。该项目的三位领导者均是著名的 IT 工程师:Robert Griesemer,参与开发 Java HotSpot 虚拟机;Rob Pike,Go 语言项目总负责人,贝尔实验室 Unix 团队成员,参与的项目包括 Plan 9,Inferno 操作系统和 Limbo 编程语言;Ken Thompson,贝尔实验室 Unix 团队成员,C 语言、Unix 和 Plan 9 的创始人之一,与 Rob Pike 共同开发了 UTF-8 字符集规范。自 2008 年 1 月起,Ken Thompson 就开始研发一款以 C 语言为目标结果的编译器来拓展 Go 语言的设计思想[3]。</blockquote>
<p><img src="/img/bVbFFJZ" alt="go-designers.png" title="go-designers.png"></p>
<blockquote>Go 语言设计者:Griesemer、Thompson 和 Pike [3]</blockquote>
<p>当时Google的很多工程师是用的都是C/C++,所以语法的设计上接近于C,Go的设计师们想要解决其他语言使用中的缺点,但是仍保留他们的优点[5]:</p>
<ul>
<li>静态类型和运行时效率</li>
<li>可读性和易用性</li>
<li>高性能的网络和多进程</li>
<li>...</li>
</ul>
<p>emmm,这些听起来还是比较玄乎,毕竟设计归设计,实现归实现,我们回顾一下现在Go的几个主要特点,编译速度、执行速度、内存管理以及并发编程。</p>
<h3>Go的编译为什么快</h3>
<p>当然,设计Go语言也不是完全从零开始,最初Go的团队尝试设计实现一个Go语言的编译前端,由基于C的gcc编译器来编译成机器代码,这个面向gcc的前端编译器也就是目前的Go编译器之一的gccgo。</p>
<p><strong>与其说Go的编译为什么快,不如先说说C++的编译为什么慢</strong>,C++也可以用gcc编译,编译速度的大部分差异很有可能来源于语言设计本身。</p>
<p>在讨论问题之前,其中需要先说明的一点是:<strong>这里比较的编译速度都是在静态编译下的</strong>。</p>
<p>静态编译和动态编译的区别:</p>
<ul>
<li>静态编译:编译器在编译可执行文件时,要把使用到的链接库提取出来,链接打包进可执行文件中,编译结果只有一个可执行文件。</li>
<li>动态编译:可执行文件需要附带独立的库文件,不打包库到可执行文件中,减少可执行文件体积,在执行的时候再调用库即可。</li>
</ul>
<p>两种方式有各自的优点和缺点,前者不需要去管理不同版本库的兼容性问题,后者可以减少内存和存储的占用(因为可以让不同程序共享同一个库),两种方式孰优孰弱,要对应到具体的工程问题上,<strong>Go默认的编译方式是静态编译</strong>。</p>
<p>回到我们要讨论的问题:C++的编译为什么慢?</p>
<p><strong>C++编译慢的主要两个大头原因[6]</strong>:</p>
<ul>
<li>头文件的include方式</li>
<li>模板的编译</li>
</ul>
<p>C++使用include方式引用头文件,会让需要编译的代码有乘数级的增加,例如当同一个头文件被同一个项目下的N个文件include时,编译器会将头文件引入到每一份代码中,所以同一个头文件会被编译N次(这在大多数时候都是不必要的);C++使用的模板是为了支持泛型编程,在编写对不同类型的泛型函数时,可以提供很大的便利,但是这对于编译器来说,会增加非常多不必要的编译负担。</p>
<p>当然C++对这两个问题有很多后续的优化方法,但是这对于很多开发者来说,他们不想在这上面有过多时间和精力开销。</p>
<p>大部分后来的编程语言在引入文件的方式上,使用了<strong>import module</strong>来代替<strong>include 头文件</strong>的方式,import解决了重复编译的问题,当然Go也是使用的import方式;在模板的编译问题上,由于Go在设计理念上遵循从简入手,所以没有将泛函编程纳入到设计框架中,所以天生的没有模版编译带来的时间开销(没有泛型支持也是很多人不满Go语言的理由)。</p>
<p>在Go 的1.5 版本中,Go团队使用Go语言来编写Go语言的编译器(也叫自举),相比于gccgo来说:</p>
<ul>
<li>提高了编译速度,但执行速度略有下降(性能细节优化还不如gcc)</li>
<li>增加了可编译的平台类型(以往受限于gcc)</li>
</ul>
<p>在此之外,Go语言语法中的关键字也是非常少的(Go1.11版本里只有25个)[7],这也可以减少编译器花费在语法解析上的时间开销。</p>
<p><img src="/img/bVbFFJ0" alt="keywords.png" title="keywords.png"></p>
<p><strong>所以在我看来,Go编译速度快,主要出于四个原因</strong>:</p>
<ul>
<li>使用了import的引用管理方式;</li>
<li>没有模板的编译负担;</li>
<li>1.5版本后的自举编译器优化;</li>
<li>更少的关键字。</li>
</ul>
<p><strong>所以为了加快编译速度、放弃C++而转入Go的同时,也要考虑一下是否要放弃泛型编程的优点。</strong></p>
<p>注:泛型可能在Go 2版本获得支持。</p>
<h3>Go的实际性能如何</h3>
<p>Go的执行速度,可以参考一个语言性能测试数据网站 —— The Computer Language Benchmarks Game[8]。</p>
<p>这个网站在不同的算法上对每个语言进行测试,然后给出时间和内存上的开销数据比对。</p>
<p>比较的语言有C++、Java、Python。</p>
<p>首先是时间开销:</p>
<p><img src="/img/bVbFFJ4" alt="time-cost.png" title="time-cost.png"></p>
<p><strong>注意</strong>:<strong>时间开销的单位是s,并且Y轴为了方便进行不同跨度上的比较,所以选取的是对数轴</strong>(即非线性轴,为1-10-100-1000的比较跨度)。</p>
<p>然后是内存开销:</p>
<p><img src="/img/bVbFFJ5" alt="mem-cost.png" title="mem-cost.png"></p>
<p><strong>注意</strong>:<strong>Y轴为了方便进行不同跨度上的比较,所以选取的是对数轴</strong>(即非线性轴,为1000-10000-100000-1000000的比较跨度)。</p>
<p>需要注意的是,<strong>语言本身的性能只决定了一个程序的最高理论性能</strong>,程序具体的性能还要取决于这个程序的实现方法,所以当各个语言的性能并没有太大的差异时,性能往往只取决于程序实现的方式。</p>
<p>通过两个图的数据可以分析:</p>
<ul>
<li>Go虽然还无法达到C++那样的极致性能,但是<strong>在大部分情况下已经很接近了</strong>;</li>
<li>Go和Java在算法的时间开销上难分伯仲,但在内存的开销上Java就要高得多了;</li>
<li>Go在上述的绝大部分情况下,至少时间和内存开销都比Python要优秀得多;</li>
</ul>
<h3>Go的并发编程</h3>
<p>Go的并发之所以比较受欢迎,网络上的很多内容集中在几个方面:</p>
<ul>
<li><strong>天生并发的设计</strong></li>
<li><strong>轻量化的并发编程方式</strong></li>
<li><strong>较高的并发性能</strong></li>
<li><strong>轻量级线程Goroutines、并发通信Channels以及其他便捷的并发同步控制工具</strong></li>
</ul>
<p>由于Go在设计的时候就考虑到了并发的支持,<strong>或者说很多特性都是为了并发而设计</strong>,这和一些后期库支持并发和第三方库支持并发的语言不同。</p>
<p><strong>所以Go的并发到底有多方便?</strong>在Go中使用并发,只需要在普通的函数执行前加上一个go关键字,就可以新建一个线程让函数在其中执行:</p>
<pre><code class="go">func main() {
go loop() // 启动一个goroutine
loop()
}</code></pre>
<p>这样带来的好处<strong>不仅仅是让并发编程更方便了</strong>,在一些特定情况下,比如Go引用一些使用了并发的库时,这些库所使用的并发也是基于Go本身的并发设计,不会存在库使用另一套并发实现的情况,这样Go调度器在处理程序中的各种并发线程时,可以有更加统一化的管理方式。</p>
<p>不过Go的并发对于程序的实现要求还是比较高的,在使用一些通信Channel的场合,稍有疏忽就可能出现死锁的问题,比如:</p>
<pre><code class="bash">fatal error: all goroutines are asleep - deadlock!</code></pre>
<p><strong>Go的并发量可以比大部分语言里普通的线程实现要高</strong>,这受益于轻量级的Goroutine,轻量化主要是它所占用的空间要小得多,例如64位环境下的JVM,它会默认固定为每个线程分配1MB的线程栈空间,而<strong>Goroutines大概只有4-8KB</strong>,之后再按需分配。足够轻量化的线程在相同的内存下也就可以有更高并发量(服务器CPU还没有饱和的情况下),同时也可以减少很多上下文切换的时间开销[9]。但是如果你的每个线程占用空间都非常大时(比如10MB,当然这是非常规需求的情况下),Go的轻量化优势就没有那么明显了。</p>
<p>Go在并发上的优点很明显,也是Go的功能目标,从语言设计上支持了并发,提供了统一便捷的工具,复杂的并发业务也需要在Go的一整套并发规范体系下进行编程,当然这肯定会牺牲部分实现自由度,但可以获得性能的提高和维护成本的下降。</p>
<p>PS:关于Go调度器的内容在这里并没有被提及,因为很难用简单的文字向读者说明该调度方式和其他调度方式的优劣,将在未来的某一篇中会细致地介绍Go调度器的内容。</p>
<h3>Go的垃圾回收</h3>
<blockquote>垃圾回收(英语:Garbage Collection,缩写为GC),在计算机科学中是一种自动的存储器管理机制。当一个计算机上的动态存储器不再需要时,就应该予以释放,以让出存储器,这种存储器资源管理,称为垃圾回收。垃圾回收器可以让程序员减轻许多负担,也减少程序员犯错的机会[10]。</blockquote>
<p>在使用Go或者其他支持GC的语言时,<strong>不用再像C++一样,手动地去释放不需要的变量占用的内容空间(free/delete)</strong>。</p>
<p><strong>的确,这很方便</strong>(对于懒人和容易忘记主动释放的人),<strong>但是也多了一些限制</strong>(暗箱操作的不透明性以及在GC处理上的性能开销)。<strong>GC也不是万能的</strong>,当遇到一些对性能要求较高的场景,还是需要记得进行一些主动释放或优化操作(比如说自定义内存池)。</p>
<p>PS:将在未来的某一篇中会细致地介绍Go垃圾回收的细节(如果你们也觉得有必要的话)。</p>
<h2>什么时候可以选择Go?</h2>
<p>Go有很多优点,编译快、性能好、天生并发以及垃圾回收,很多比较有特色的内容也还没有说到(比如gofmt)。</p>
<p>Go语言也有很多缺点,比如<strong>第三方库支持还不够多</strong>(相比于Python来说就少的太多了)、<strong>支持编译的平台还不够广</strong>、还有<strong>被称为噩梦的依赖版本管理</strong>(已经在改善了,但是还没有达到完全可靠的程度)。</p>
<p><strong>所以到底Go适合做什么,不适合做什么?</strong></p>
<p>分析了这么多后,这个问题其实很难回答,但我们可以选择先从不适合的领域把Go剔除掉,看看我们会剩下什么。</p>
<h3>Go不适合做什么</h3>
<ul>
<li>极致高性能优化的场景,你可能需要使用C/C++,甚至是汇编;</li>
<li>简单流程的脚本工具、数值分析、深度学习,可能Python更适合(至少目前是);</li>
<li>搭一个博客或网站,PHP何尝不是天下第一的语言呢;</li>
<li>如果你想比较方便找到一份的后端工作,绝大部分公司的Java岗一直缺人(在实际生产过程中,目前Go仍没有比Java表现得好太多,至少没有好到让一个部门/公司将核心业务重新转向Go来进行重构);</li>
<li>...</li>
</ul>
<p>你可以找到类似上面那样的很多场景,你可能会发现Go并不能那么完美地替代掉谁。</p>
<h3>Go适合做什么</h3>
<p>最后,到了我们的终极问题,<strong>Go到底适合做什么?</strong></p>
<p>读到这里你可能会觉得,好像是我把Go的特性吹了一遍,然后突然告诉你可能Go不适合你。</p>
<p><strong>Go天生并发,面向并发</strong>,所以Go的定位一直很清楚,从最浅显的视角来看,至少Go作为一个有较高性能的并发后端来说,是具有非常大的诱惑力的。</p>
<p><strong>尤其对于后端相关的程序员而言</strong>,在某些业务功能的<strong>初步实现</strong>上,简洁的语法、内置的并发、快速的编译,都可以让你更加高效快速地完成任务(前提是Go的内容足以完成你的任务),不用再去担忧编译优化和内存回收、不用担心过多的时间和内存开销、不用担心不同版本库之间的冲突(静态编译)以及不用担心交叉编译平台适配问题。</p>
<p><strong>大部分情况下,编写一个服务,你只需要:实现、编译、部署、运行</strong>。</p>
<p><strong>高效快速,足够敏捷</strong>,这在企业的绝大部分项目的初期都是适用的,这也是大部分项目对开发初期的要求。当一个项目或者服务真的可以发展下去,需求的确触碰到Go的天花板时,再考虑使用更加好的语言或方法去优化也为时不晚。</p>
<p>简而言之,尽管Go的过于简洁带来了很多问题(有些人说的难听点叫过于简单),Go所具有的优点,可以让大部分人用编程语言这种工具,来解决对他们而言更加重要的问题。</p>
<p><strong>Go语言不是银弹,但它的确能有效地解决这些问题。</strong></p>
<h2>参考文章</h2>
<ul>
<li>[1] RUNOOB Go语言教程 菜鸟教程,<a href="https://link.segmentfault.com/?enc=WUjmQZsfheV64Z53nLp3oA%3D%3D.B%2BYRS4hGpYZ66XYuqsQ2mJVuI67YX7PnJj5zDKFyOWFlwUeUdr3JMUAMamdm1EI0" rel="nofollow">https://www.runoob.com/go/go-...</a>
</li>
<li>[2] 没有银弹:软件工程的本质性与附属性工作(No Silver Bullet—Essence and Accidents of Software Engineering),<a href="https://link.segmentfault.com/?enc=ibSBVks7MyoxRjiQMCKLxA%3D%3D.lu3Yfdlc9CPNmFsX5CAGFj%2B3dypIZdyox2NnIPUMdL%2FhXXlMLrmCPq22l7Dxtcrskwv9J%2Bc%2F%2Fw9qLqHOYnt3VQ%3D%3D" rel="nofollow">http://worrydream.com/refs/Br...</a>
</li>
<li>[3] The way to Go,<a href="https://link.segmentfault.com/?enc=JNIRPIIy%2BWwj9dBMcAh9qg%3D%3D.%2BNE8h2tT1YYHq6CZl6VHGtS7SA3kzxWqXZPvD%2F135PdvCuQxu1kU0JwtIXLQ4gZdlDr0jAwRYSBC8X0GOr9x01pbpr7cu52EiNd0jHtL7Os%3D" rel="nofollow">https://github.com/unknwon/th...</a>
</li>
<li>[4] 我为什么选择使用 Go 语言?,<a href="https://link.segmentfault.com/?enc=3cKZrV%2B1mAd81vThsjkR4w%3D%3D.MzCXL0RZlP6H2bNDcVtXEFITTU53fgvN5dunBgz3st8wKksgTmUo6Hi20fhJnczr7alpgGLSL%2F3KkSPzC53xDw%3D%3D" rel="nofollow">https://juejin.im/entry/5705f...</a>
</li>
<li>[5] Wiki - Go,<a href="https://link.segmentfault.com/?enc=dxdqB1oPyC4ex6ssjOWQLQ%3D%3D.Fy4SKe2Hx9RrKI7cAadg%2BCAoe7YHjVUDIPbUAQoKc%2FVLRFbJuHJAfJvEuuKUjSP%2B" rel="nofollow">https://zh.wikipedia.org/wiki/Go</a>
</li>
<li>[6] 为什么 C++ 编译速度比 Java 慢得多?,<a href="https://link.segmentfault.com/?enc=0hUQ9KMoEOTzL610mLBVqg%3D%3D.C2n2%2BnRBxfomODj0SHiN2sxKr3zJJ5b9Xgi9%2Bu0ua3w7256KTSLRuSCecGn14Qdx" rel="nofollow">https://www.zhihu.com/questio...</a>
</li>
<li>[7] Github - eighmcculloch/keywords,<a href="https://link.segmentfault.com/?enc=8a%2Bv6El2Lcvuxt5ab3gYTQ%3D%3D.Fyp0lUYhjwysA17DnqclZSd2GsR8Ptfz2Hq16V1Q%2FpcteC7kw98oT65WI%2BKsqI2K" rel="nofollow">https://github.com/leighmccul...</a>
</li>
<li>[8] The Computer Language Benchmarks Game,<a href="https://link.segmentfault.com/?enc=l24AjnQXErY3ShyNnMajTg%3D%3D.OkiJzXqskaxHEzWKZ4jLThHmcegY%2FgNqPV55ePxjqb%2ByflqHgNeRQS0M5rokusOIaSmKE0E3KxZ7Lg%2FXayETzcB0uduuy%2BWG5RhEFBVP6QM%3D" rel="nofollow">https://benchmarksgame-team.p...</a>
</li>
<li>[9] 为什么能有上百万个 Goroutines,却只能有上千个 Java 线程?,<a href="https://link.segmentfault.com/?enc=AF3oEc0OCU1kmkQAZdxpJg%3D%3D.2hAcRAHh8ANKGKTMor504OatesjfJ60SM%2Fd%2BZa3yI1gc6db6zABJPczSLD4CkmGVZTt8J8VzxI1naU43zYrm6tYgS%2B%2FdAAll94l%2BMZbuB7M%3D" rel="nofollow">https://www.infoq.cn/article/...</a>
</li>
<li>[10] Wiki - 垃圾回收,<a href="https://link.segmentfault.com/?enc=RxmVztj%2BjMMmsm76T54j2g%3D%3D.r5DzT%2BglIvdAre55mL0RnPJOk4FwN0kUSIwGDk1cFHdLR6xU7guDGB7WrGimali%2FY8MVuwu2ggxR9et6kDU5%2FOMKeGt9mEHrPO%2BQeCX4o48%3D" rel="nofollow">https://en.wikipedia.org/wiki...</a>
</li>
</ul>
<h2>扩展阅读</h2>
<p>在调查Go的过程中,发现了一些比较有意思、或者比较实用的文章,一并附在这里。</p>
<ul>
<li>
<a href="https://link.segmentfault.com/?enc=IIfuJKbvgr1DVvJPwn9VaA%3D%3D.v72orOkW2PO5TAUaxNYCBN1slElOHtC%2FaPZJKqMf4x6%2B%2B3Glx6i3ayWg0VY%2BNthIoEZO9cXHdJlcYmOQv7y5GA%3D%3D" rel="nofollow">我为什么选择使用 Go 语言?</a>,该文写于2016年,在我的文章基本构思完成的时候,偶然看到了这篇文章,作者有很多早期Go版本的开发经验,里面有更多的细节都是出自于工程师的经验之谈,我发现其中的部分想法和我不谋而合,你可以把这篇文章当作本文的后续扩展阅读,不过要注意文章的时效,可能提及到的一些Go的缺点现在已经被改进了。</li>
<li>
<a href="https://link.segmentfault.com/?enc=h0OXLrGtUGWp9p0b5orPtg%3D%3D.Mkg7AR6c%2FZIsI4k%2BRFaMBilQVi3g3Dwkrt8PrGExQN5nk8%2BJG%2BNINFRtCa3AEbhY2srUwmNZ4BRQYShd12c6lg%3D%3D" rel="nofollow">C/C++编译器的工作过程</a>,主要是供不熟悉C系的朋友了解一下编译器的工作过程。</li>
<li>
<a href="https://link.segmentfault.com/?enc=KRyb%2FyWGewEk%2BgFtyKx2QA%3D%3D.L%2BusCpdigbj4tCduXdMjvYdZyCpnPnp3OsH880FgUmo%2FCW%2BFkbWhQFLpYt8Ar0FV%2BA3aQzA8GHLz0hKD9qyH6jDM6dEhLtj1LWPHKw3Imlg%3D" rel="nofollow">The Computer Language Benchmarks Game</a>,一个对各个语言进行性能测试的网站,里面的算法具有一定的代表性,但是不能代表所有工程可能遇到的情况,仅供参考。</li>
<li>
<a href="https://link.segmentfault.com/?enc=ueU0HzsRDB3JytOcSd%2FS8Q%3D%3D.A0ES%2Bk97r8WM30%2BRfFMhDMX4T1BboRM1VPl7Dtp0R6MNTYJKhXVaoPIaNVJ%2FK4sr" rel="nofollow">为什么 Go 语言在某些方面的性能还不如 Java?</a>,这是知乎上一个2017年开始有的问题,你可以看到很多人对于这个问题的分析,从多个角度来理解语言之间的性能差异。</li>
<li>
<a href="https://link.segmentfault.com/?enc=ffeE%2Fat7JM0HEkGVmfVKoQ%3D%3D.5hIqIiGVwfgKOplJWTHc38vJG9HjW%2FtyCVljTGUv8rjFqEN6HU1glxaZQA9Nc1gL" rel="nofollow">go-wiki WhyGo</a>,Go的Github仓库上维护的Wiki中,有一篇关于WhyGo的文章整理,不过大部分是英文,里面主要是很多关于“为什么我要选择Go”的软硬稿。</li>
<li>
<a href="https://link.segmentfault.com/?enc=Fhg2fdaFemLOd4Gl49WA%2BQ%3D%3D.dO72ykjux9bnrnl8UOAbXbPKU8BtR4GL0D%2FSiHhKGBR34%2FDP8XnQDA7aVdtPkIy7" rel="nofollow">为什么要使用Go语言,Go语言的优势在哪里</a>,这个知乎的提问更早,是来自2013年的Yvonne YU用户,在Go的早期其实是具有很大的争议的,你可以看到大家在各个问题上的博弈。</li>
<li>
<a href="https://link.segmentfault.com/?enc=thVYEJH5LjPwe9wigS0CWw%3D%3D.qXb6v753ti%2BeDP0Wtv%2FBV%2Fd%2FSgfFFGrslWNUk%2FjfZ0f7y74BL7N0mfnGWjnZFwt4" rel="nofollow">哪些公司在使用Go</a>,Go的Github仓库上维护的Wiki中,有一篇关于全球都有哪些公司在使用Go,不过提供的信息大部分只有一个公司名,比如国内有阿里巴巴(而人家大部分都招Java),可以看看但参考性不大。</li>
<li>
<a href="https://link.segmentfault.com/?enc=FtA%2Bd5GRwmqj2V5fq1QW3A%3D%3D.5%2BJmiGJNpMOkaSn0vRn0VHFtAX%2F1Xt8e6%2BAwof35L27Ky%2Fi2zitVrGxtnYPlCWB0" rel="nofollow">Go 语言的优点,缺点和令人厌恶的设计</a>,这是Go语言中文网上一篇2018年的文章,如果你对语言本身的一些特性的设计感兴趣,你可以选择看看,作者从很多语法层面上介绍了Go的优点和缺点。</li>
<li>
<a href="https://link.segmentfault.com/?enc=iRo%2FmQ25%2FWJmxl5IaM6azw%3D%3D.%2FHoeSfhHgx7LjokIIAa7el8ChXO0Oc8Q65OsmxvAZYnswGt2Rgxd0iu6btQm6BeU" rel="nofollow">Ruby China - 瞎扯淡 真的没必要浪费心思在 Go 语言上</a>,这是我无意中找到的一篇有名的帖子,这个问题始于2013年,在Ruby China上,其中也是大佬们(可能)从各个角度来辩论Go是否值得学习,可以当作武侠小说观看。</li>
<li>
<a href="https://link.segmentfault.com/?enc=xhQxhGcQhQ5oiKjS6IKD7A%3D%3D.LnrxniYC0AEgHEB4EcuawpTjsAaOcEQ3tn54%2Bl0Zvjan3CYCunExcQXOVWPBPpzww3VsRPmR2uvkF1tAPUSWOs4fS4Sne0hSocNkdlE6Kck%3D" rel="nofollow">The way to Go - 3.8 Go性能说明</a>,《The way to Go》这本书上为数不多关于Go性能问题的说明。</li>
<li>
<a href="https://link.segmentfault.com/?enc=o3QGNyTye5EkrBEcY3j7sg%3D%3D.WUlR3kq3nRUX%2F9NQXzGdeJek%2Ffk0XaGa3Q1XpIn2SV2qol5lA8GPTN3VhrmrvVdL" rel="nofollow">C++开发转向go开发是否是一个好的发展方向?</a>,2014年知乎上关于C++和Go的一个讨论,其实我觉得“如果选择一个并不意味着就要放弃另一个”,程序员不是研究语言的,也不应该是只靠某一门语言吃饭。</li>
<li>
<a href="https://link.segmentfault.com/?enc=b3WNF1sdErX%2BYN%2B5i0v34g%3D%3D.%2BR4RhFd4LIZAuJ8U%2Bpr4o8E5tHO0RvXU0SYzwi%2Bw9Wlfw32bJheafCKXdmeRLjaFEsGBJZELcI1nFf%2B5FZwicA%3D%3D" rel="nofollow">我为什么放弃Go语言 Liigo</a>,嗯,2014年,仍旧是Go争议很大的时候,CSDN上一篇阅读数很高的文章,作者从自己的角度对Go进行批判(Go早期的确是有不少问题),你可以看到早期Go的很多问题,也可以斟酌这些问题对你是否重要以及到底在2020年的Go中有没有被解决。</li>
<li>
<a href="https://link.segmentfault.com/?enc=wRbtsNNAsdyNMMtJ1aED4g%3D%3D.1m64t2gEExNVtMEncMr2N%2FzVDpyNDSHKaFIBq%2FpLAl9TV7xfa%2B8z0DQisuCibM%2FZ" rel="nofollow">Golang 本身是用什么语言写的?</a>,一个关于编译的有趣的问题,可以适当了解。</li>
<li>
<a href="https://link.segmentfault.com/?enc=aEh8DqnINRw693iP1ry5TQ%3D%3D.vtemtDEu3GJMzEeyd5EydnQ9PSLlSbZxbeGPiWO%2BCYmziCKK7K%2BoQqDz8kJRmrUw" rel="nofollow">搞懂Go垃圾回收</a>,一篇还算比较新的分析Go垃圾回收问题的文章。</li>
<li>
<a href="https://link.segmentfault.com/?enc=jIuP6inVVKAlouLgXvSliQ%3D%3D.i4bp2g6tua9efDritRd%2Fa1nnedpEsE3H81%2FWF1ZVbXhHkD0hNM4EVrM0u8uyMbJNNGauOBIAvQDB7wjhRlOSxQ%3D%3D" rel="nofollow">有趣的编程语言:Go 语言的启动时间是 C 语言的 300 多倍,C# 的关键字最多</a>,这篇InfoQ文章其实算是一个典型的标题党,主要使用的是一个Github上关于各个语言HelloWorld程序启动时间的测试数据(<a href="https://link.segmentfault.com/?enc=gKj%2B%2FFpYDjW7lySTCEmrZA%3D%3D.d8YLNCOShjoX5vtM9Q4v6NJ1x5VLJ96mTA4pgnQ1zTzjrLmUsufZP5OmSglA%2FgGe" rel="nofollow">https://github.com/bdrung/sta...</a>,使用gccgo编译的Go程序的启动时间非常地长,的确是C的300多倍,但使用GC编译的Go程序启动时间只是C的2倍。</li>
<li>
<a href="https://link.segmentfault.com/?enc=nNtVCEDz6TrlNyAwtwWbQQ%3D%3D.T%2BngLYwxKtnrNjzqiyOzPG6JQJWha%2Bm8wbD58KovTHoM0ffnyoDs1ykSJCjNjCObl9nwoUdiNY1mRZznkS7Q3Q%3D%3D" rel="nofollow">Go 语言的历史回顾</a>,我一直在寻找一个整理Go的版本变动细节的文章,在Go的官方文档和各种书籍上寻找无果时,在InfoQ上找到了一篇还算跟踪地比较新的(Go 1.0 - Go 1.13)文章,对于初学者而言,知道语言的变化也是很重要的(比如方便的知道哪些问题解决了,哪些还没有被解决),可能之后会拓展性的写一篇关于这个的文章。</li>
</ul>