<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://xuyisen.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://xuyisen.github.io/" rel="alternate" type="text/html" /><updated>2025-06-07T08:43:04-07:00</updated><id>https://xuyisen.github.io/feed.xml</id><title type="html">Yisen Xu</title><subtitle>PhD Candidate in Software Engineering</subtitle><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><entry><title type="html">机器学习算法学习</title><link href="https://xuyisen.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0/" rel="alternate" type="text/html" title="机器学习算法学习" /><published>2020-01-06T13:07:46-08:00</published><updated>2020-01-06T13:07:46-08:00</updated><id>https://xuyisen.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0</id><content type="html" xml:base="https://xuyisen.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E7%AE%97%E6%B3%95%E5%AD%A6%E4%B9%A0/"><![CDATA[<h3 id="机器学习介绍">机器学习介绍</h3>

<hr />

<p><img src="/images/302.png" alt="图片描述" />
机器学习其实只有三个步骤。第一个步骤就是找一个function，第二个步骤是让machine可以衡量一个function是好是坏，第三个步骤是让machine有一个自动的方法，挑出最好的function。</p>

<h2 id="机器学习相关的技术">###机器学习相关的技术</h2>

<p><img src="/images/303.png" alt="图片描述" /></p>

<h4 id="监督学习">监督学习</h4>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Int</span> <span class="o">-&gt;</span> <span class="nc">Color</span>     <span class="c1">//Color 取值为 Red, Yellow, Blue </span>
<span class="err">\</span><span class="n">a</span> <span class="o">=</span> <span class="o">[</span><span class="nc">Red</span><span class="o">,</span><span class="nc">Yellow</span><span class="o">,</span><span class="nc">Blue</span><span class="o">]</span> <span class="o">!!</span> <span class="o">(</span><span class="n">abs</span> <span class="n">a</span> <span class="o">%</span> <span class="mi">3</span><span class="o">)</span>
</code></pre></div></div>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="论文阅读笔记" /><category term="machine_learning" /><category term="李宏毅" /><summary type="html"><![CDATA[机器学习介绍]]></summary></entry><entry><title type="html">高阶函数初探（五）</title><link href="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2-%E4%BA%94/" rel="alternate" type="text/html" title="高阶函数初探（五）" /><published>2018-12-10T07:37:02-08:00</published><updated>2018-12-10T07:37:02-08:00</updated><id>https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2%EF%BC%88%E4%BA%94%EF%BC%89</id><content type="html" xml:base="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2-%E4%BA%94/"><![CDATA[<p>这周主要根据上次讨论的内容统计数据和作图，但是在统计数据的过程中发现了不少问题，因此对实验又重新进行了更新，提高数据的准确度。</p>

<!--more-->

<h3 id="统计数据">统计数据</h3>

<p>按照之前的讨论方向，除了之前的数据之外还需要增加以下几个内容：</p>

<ul>
  <li>高阶函数声明的每种类型的调用次数(&gt;=2,1,0)</li>
  <li>private 类型的高阶函数的声明和调用情况，存不存在private 高阶函数调用次数为0，（Scala 语言默认函数为public）</li>
  <li>统计Scala语言中高阶函数和lambda之间的关系，统计交并集</li>
  <li>统计一个项目中是否存在20%的人写了80%的高阶函数代码</li>
  <li>统计高阶函数调用每种类型的作者数量</li>
</ul>

<h3 id="发现的问题">发现的问题</h3>

<p>在统计第一个数据时，即每种类型的调用次数时发现调用次数为0的声明太多了：<br />
<img src="/images/207.png" alt="图片描述" /><br />
这个太不符合常理，一般除了接口外不会有人声明函数不调用，于是我就简单的查看一些没有被我程序检查出来的调用，发现：</p>

<ul>
  <li>有些程序没有被Scalameta识别出来是函数调用：
    <ul>
      <li><img src="/images/208.png" alt="图片描述" /></li>
      <li>图片中的函数是一个返回一个函数的高阶函数，它在另一个val 定义中被调用，但是在scalameta看来就是一个字符串并不是函数调用。</li>
      <li><img src="/images/209.png" alt="图片描述" /></li>
      <li>仅仅是加了一个括号就变成了调用（Term.Apply()).</li>
    </ul>
  </li>
  <li>有些程序调用了其他包里面的函数不容易分析：
    <ul>
      <li><img src="/images/300.png" alt="图片描述" /></li>
      <li>同一个包里面所有函数</li>
      <li><code class="language-plaintext highlighter-rouge">-</code>代表导入一个包里面的所有类，类似java里面的<code class="language-plaintext highlighter-rouge">*</code>, 有些函数调用在一个文件中只出现了一次而且前面也没有类修饰，只是像<code class="language-plaintext highlighter-rouge">getFile(fileName)</code> 这样就不容易分析这个函数调用到底属于谁。</li>
    </ul>
  </li>
</ul>

<p>以上几个问题都是在在统计中发现的，其他的一些情况像嵌套函数暂时还没有列出来。</p>

<h3 id="更新思路">更新思路</h3>

<p>介于上面的问题，我决定尝试使用语义数据库来尝试一下，之前跟玄老师介绍过，这个是Scalameta开源组织另一个工具，但是我在几个大项目中(spark,scala..,)中尝试了编译中断，无法通过编译。这周我将这个工具尝试用在其他的项目上，经过两三天的配置项目，最终得到了11个项目的语法数据库。</p>

<h4 id="语法数据库">语法数据库</h4>

<p>语法数据库的内容：</p>

<p><img src="/images/301.png" alt="图片描述" /></p>

<p>根据语法数据库的内容，我们可以在Symbol中找到函数的声明，在Occurrences中查找函数的调用。通过语法数据库我们可以得到：</p>

<ul>
  <li>所有函数声明（普通函数，高阶函数）</li>
  <li>函数声明是否是private</li>
  <li>函数声明中高阶函数的类型</li>
  <li>lambda函数声明(lambda是有函数声明的）</li>
  <li>函数是否是局部函数（嵌套函数）</li>
  <li>所有函数的调用（普通函数，高阶函数）</li>
  <li>函数调用在源代码中的具体位置</li>
</ul>

<p>但是语法数据库我们无法得到：</p>

<ul>
  <li>函数调用的类型</li>
  <li>没有声明的lambda匿名函数的数量</li>
</ul>

<p>针对后两个我们无法得到的东西我们可以通过其具体的位置，然后通过语法分析，字符串匹配来得出。</p>

<h4 id="使用语法数据库的初步结果">使用语法数据库的初步结果</h4>

<ul>
  <li>11个得到语法数据库的项目：
    <ul>
      <li>bfg</li>
      <li>fpinscala</li>
      <li>framework</li>
      <li>gatling</li>
      <li>gitbucket</li>
      <li>lila</li>
      <li>sbt</li>
      <li>scalaz</li>
      <li>scala-js</li>
      <li>scalding</li>
      <li>shapeless</li>
    </ul>
  </li>
  <li>高阶函数声明和调用对比</li>
</ul>

<table>
  <thead>
    <tr>
      <th style="text-align: center"> </th>
      <th style="text-align: center">语法分析高阶函数声明</th>
      <th style="text-align: center">语法分析调用</th>
      <th style="text-align: center">语义分析声明</th>
      <th style="text-align: center">语义分析调用</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: center">bfg</td>
      <td style="text-align: center">7</td>
      <td style="text-align: center">3</td>
      <td style="text-align: center">27</td>
      <td style="text-align: center">11</td>
    </tr>
    <tr>
      <td style="text-align: center">fpinscala</td>
      <td style="text-align: center">464</td>
      <td style="text-align: center">416</td>
      <td style="text-align: center">700</td>
      <td style="text-align: center">910</td>
    </tr>
    <tr>
      <td style="text-align: center">framework</td>
      <td style="text-align: center">176</td>
      <td style="text-align: center">151</td>
      <td style="text-align: center">468</td>
      <td style="text-align: center">328</td>
    </tr>
    <tr>
      <td style="text-align: center">gitbucket</td>
      <td style="text-align: center">62</td>
      <td style="text-align: center">256</td>
      <td style="text-align: center">138</td>
      <td style="text-align: center">624</td>
    </tr>
    <tr>
      <td style="text-align: center">gatling</td>
      <td style="text-align: center">101</td>
      <td style="text-align: center">110</td>
      <td style="text-align: center">315</td>
      <td style="text-align: center">379</td>
    </tr>
    <tr>
      <td style="text-align: center">sbt</td>
      <td style="text-align: center">512</td>
      <td style="text-align: center">622</td>
      <td style="text-align: center">710</td>
      <td style="text-align: center">1202</td>
    </tr>
    <tr>
      <td style="text-align: center">shapeless</td>
      <td style="text-align: center">97</td>
      <td style="text-align: center">36</td>
      <td style="text-align: center">502</td>
      <td style="text-align: center">102</td>
    </tr>
    <tr>
      <td style="text-align: center">lila</td>
      <td style="text-align: center">258</td>
      <td style="text-align: center">391</td>
      <td style="text-align: center">453</td>
      <td style="text-align: center">699</td>
    </tr>
  </tbody>
</table>

<h4 id="偶然发现的数据">偶然发现的数据</h4>

<p>在查找如何使用配置semanticdb的时候，偶然发现了scalameta作者收集到的一些数据（所用到的工具版本不一致），作者一共统计了91个项目的数据，其中有几个是我们20个项目中的，我认为可以作为后面实验的补充数据，至少可以确定能够配置成功。<br />
GitHub 网址：  https://github.com/olafurpg/scala-experiments<br />
91个项目列表：  https://docs.google.com/spreadsheets/d/1btkCiF30Wb9MJti6LDc9og788XqXBKgwEhIdKb9aloc/edit#gid=1799045603</p>

<h4 id="之后的实验打算">之后的实验打算</h4>

<ul>
  <li>增加更多的项目并再次尝试配置没有成功的项目。</li>
  <li>将语法分析和语义分析的数据结合起来再加上作者。</li>
  <li>按照基本数据统计之前讨论的所需要的数据。</li>
</ul>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="高阶函数" /><category term="scala" /><category term="高阶函数" /><summary type="html"><![CDATA[这周主要根据上次讨论的内容统计数据和作图，但是在统计数据的过程中发现了不少问题，因此对实验又重新进行了更新，提高数据的准确度。]]></summary></entry><entry><title type="html">《Programmers do not favor lambda expressions for concurrent object-oriented code》阅读笔记</title><link href="https://xuyisen.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/Programmers-do-not-favor-lambda-expressions-for-concurrent-object-oriented-code-%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/" rel="alternate" type="text/html" title="《Programmers do not favor lambda expressions for concurrent object-oriented code》阅读笔记" /><published>2018-11-27T11:58:51-08:00</published><updated>2018-11-27T11:58:51-08:00</updated><id>https://xuyisen.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/%E3%80%8AProgrammers%20do%20not%20favor%20lambda%20expressions%20for%20concurrent%20object-oriented%20code%E3%80%8B%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0</id><content type="html" xml:base="https://xuyisen.github.io/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/Programmers-do-not-favor-lambda-expressions-for-concurrent-object-oriented-code-%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/"><![CDATA[<p>原文链接： https://link.springer.com/content/pdf/10.1007%2Fs10664-018-9622-9.pdf<br />
作者：MSebastian Nielebock，Robert Heumüller，Frank Ortmeier
文章来源： Empir Software Eng 2018
简介： 本文针对<code class="language-plaintext highlighter-rouge">lambda expression</code>，提出了<code class="language-plaintext highlighter-rouge">concurrent applications</code>与<code class="language-plaintext highlighter-rouge">lambda expression</code>可能存在一定联系，并通过一系列实验和实验数据的分析验证了自己的观点。</p>

<!--more-->

<h2 id="motivation-and-research-questions">Motivation and Research Questions</h2>

<p><code class="language-plaintext highlighter-rouge">lambda expressions</code>有很优越性，它允许声明匿名函数，能够更容易将行为转化为程序组件。在一些纯(purity)表达式中，能够保证代码没有副作用等等，这些好处推动了程序员更加广泛的使用<code class="language-plaintext highlighter-rouge">lambda expressions</code>。</p>

<h3 id="前人主要研究的问题">前人主要研究的问题</h3>

<p><code class="language-plaintext highlighter-rouge">Järvi and Freeman 2010; Gyori et al. 2013</code> 等人在自己的论文中声明了<code class="language-plaintext highlighter-rouge">lambda expressions</code>的几个优点或者影响即：</p>

<ul>
  <li>减少了代码数量</li>
  <li>促进了并行应用的发展</li>
  <li>使组合软件功能更加容易</li>
  <li>对软件的性能上没有非常严重的不良影响</li>
</ul>

<p>本文主要针对第二点做了更深入的研究。</p>

<h3 id="本文主要的研究问题">本文主要的研究问题</h3>

<ul>
  <li>并发上下文中lambda表达式的突出程度如何，分析的语言在这方面有何不同？ (三种语言c#,c++,java，3000个项目)</li>
  <li>在并发上下文中，开发人员是更喜欢非捕捉lambda(non-capturing)还是捕捉lambda(capturing) <br />
non-capturing:即在并发上下文中lambda表达式没有引入外部变量，更安全。<br />
<img src="/images/191.png" alt="图片描述" /><br />
capturing:即在并发上下文中lambda表达式引入了外部变量，不安全。<br />
<img src="/images/190.png" alt="图片描述" /></li>
  <li>除了并发编程之外，还有哪些其他用例是lambda表达式的典型用例？</li>
</ul>

<h2 id="experimental-analysis-of-the-research-questions">Experimental Analysis of the Research Questions</h2>

<h3 id="rq1">RQ1</h3>

<p>针对第一个RQ,本文主要做了以下实验：</p>

<ul>
  <li>统计了3000个c#（1000）,java（1000）,c++（1000）开源项目(github star ranking)</li>
  <li>统计了所有项目中包含lamda 表达式的项目的数量<br />
<img src="/images/192.png" alt="图片描述" /></li>
  <li>统计了所有项目中包含并行上下文项目的数量<br />
<img src="/images/193.png" alt="图片描述" /></li>
  <li>统计了所有项目中既包含lambda表达式又包含并行上下文项目的数量<br />
<img src="/images/194.png" alt="图片描述" /></li>
  <li>定义了两个度即强度(Intensity),采用度(Utilization)
    <ul>
      <li>intensity of lambda expression usage in concurrent contexts:<br />
  <img src="/images/195.png" alt="图片描述" /><br />
  p:为一个项目<br />
  numberLambdaInConcContext(p) : 为求出一个项目中在并行上下文中有lambda表达式这种情况的数量的函数
  numberLambda(p)：为求出一个项目中所有lambda表达式的数量的函数</li>
      <li>utilization of lambda expressions<br />
  <img src="/images/196.png" alt="图片描述" /><br />
  p:为一个项目<br />
  numberFilesWithLambdaInConcContext(p)：为求出一个项目在并行上下文中有lambda表达式所在文件数量的函数<br />
  numberFilesWithConcContext(p):为求出一个项目中存在并行上下文所有文件数量的函数</li>
    </ul>
  </li>
  <li>针对两个<code class="language-plaintext highlighter-rouge">度</code>,利用<code class="language-plaintext highlighter-rouge">Kruskal-Wallis test</code>和<code class="language-plaintext highlighter-rouge">Dunn’s test</code>来探索三种语言项目的相关性。 
<img src="/images/197.png" alt="图片描述" /><br />
<img src="/images/198.png" alt="图片描述" /><br />
<img src="/images/199.png" alt="图片描述" /></li>
</ul>

<p>结论：</p>
<ul>
  <li>C＃项目比C ++和Java项目在并发上下文中具有明显更高的lambda表达式强度。</li>
  <li>在所有三种语言中，并发上下文不是lambda表达式的主要用例(应用场景)</li>
  <li>与其他两种语言的程序员相比，C＃程序员在实现并发上下文时更频繁地应用lambda表达式。</li>
  <li>除了这些显着差异之外，结果表明大量项目可以在并发上下文中增加lambda表达式的应用。</li>
</ul>

<h3 id="rq2">RQ2</h3>

<p>针对第二个RQ,本文主要做了以下实验：</p>

<ul>
  <li>还是之前的3000个项目</li>
  <li>统计了所有项目中 <code class="language-plaintext highlighter-rouge">capturing lambda</code> 和<code class="language-plaintext highlighter-rouge">non-capturing lambda</code>的数量<br />
 <img src="/images/200.png" alt="图片描述" /></li>
  <li>求出采用度(Utilization) ,利用<code class="language-plaintext highlighter-rouge">Kruskal-Wallis test</code>和<code class="language-plaintext highlighter-rouge">Dunn’s test</code>来探索三种语言项目的相关性<br />
 <img src="/images/201.png" alt="图片描述" /></li>
</ul>

<p>结论：</p>
<ul>
  <li>尽管捕获lambda表达式可能会引入额外的副作用，但所有被调查的编程语言的开发人员在并发中比在一般应用程序中更多地应用lambda表达式，与预期相反。</li>
</ul>

<h3 id="rq3">RQ3</h3>

<p>针对第三个RQ,本文主要做了以下实验：</p>

<ul>
  <li>还是之前的3000个项目</li>
  <li>根据源代码文件的名字（定性分析，没给具体的方法，自己看的？），将该文件的应用场景分为以下几类：<br />
<img src="/images/202.png" alt="图片描述" /></li>
  <li>统计了每种语言应用场景的分布情况(文件数量)<br />
 <img src="/images/203.png" alt="图片描述" /> 
 <img src="/images/204.png" alt="图片描述" /> 
 <img src="/images/205.png" alt="图片描述" /></li>
</ul>

<p>结论：</p>

<ul>
  <li>开发人员倾向于在自动测试中，在算法和用户界面的实现中使用lambda表达式</li>
  <li>三种语言的应用场景也不尽相同：<br />
<img src="/images/206.png" alt="图片描述" /></li>
</ul>

<h2 id="related-work">Related Work</h2>

<h3 id="analyzes-on-the-adoption-of-lambda-expressions">Analyzes on the Adoption of Lambda Expressions</h3>

<p>相关工作里面对我们有用的只有这个感觉，对是否采用lambda表达式进行分析</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Mazinanian et al. (2017)</code>等最近对Java中的lambda表达式进行了一项研究。特别是，他们分析了来自GitHub的241个开源项目的历史数据，以找到开发人员最近添加了lambda表达式的项目。然后他们采访了有意义的开发人员，以发现他们插入具体lambda表达式的原因。他们的主要见解是lambda表达式的采用正在增加，并且大多数lambda都是手动插入的。此外，分析表明，由于几个原因，例如缺少异常处理，开发人员不使用标准库提供的许​​多功能接口。此外，在他们的定性研究中确定了采用lambda表达式的几个关键原因。这些包括减少代码大小，避免类实现，包装行为，迁移到Java 8或强制使用lambda表达式的库。除了这些抽象的原因，他们还确定了lambda表达式的一些特定用例，例如，实现了监听器和回调，简化了测试，以及多线程和异常处理。与我们的研究相反，他们只调查了一种编程语言中的lambda表达式的使用，即Java。此外，我们还进行了跨语言分析，可以更深入地了解编程语言之间的差异。这可以帮助语言设计者通过学习其他语言的实现来改进他们当前的lambda表达式设计</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Uesbeck et al. (2016)</code>等对58名不同经验水平的参与者进行了用户实验。在本实验中，他们被要求通过使用迭代器接口或lambda表达式来解决C++中的编程任务。他们的研究结果表明，有经验的用户更有可能正确应用lambda表达式。 这表明我们必须仔细选择我们分析中使用的项目，因为大量新手开发人员正在处理的项目可能具有更高的错误使用的lambda表达式。</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">Tsantalis et al. (2017)</code>等开发了一个Java重构工具，旨在通过插入lambda表达式来减少代码克隆。 他们表明，他们的工具可以在开源项目中正确地重构57-60％的类型-2（除了标识符名称语法相同）和类型-3（添加或删除语句）克隆。 特别是，他们指出，与生产代码中的克隆相比，驻留在测试代码中的克隆比例更高，可以成功重构（71％对51％）。这些发现揭示了lambda表达式的潜在用例，即克隆代码减少和自动测试。</p>
  </li>
</ul>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="论文阅读笔记" /><category term="Lambda" /><category term="expression" /><category term="Concurrency" /><summary type="html"><![CDATA[原文链接： https://link.springer.com/content/pdf/10.1007%2Fs10664-018-9622-9.pdf 作者：MSebastian Nielebock，Robert Heumüller，Frank Ortmeier 文章来源： Empir Software Eng 2018 简介： 本文针对lambda expression，提出了concurrent applications与lambda expression可能存在一定联系，并通过一系列实验和实验数据的分析验证了自己的观点。]]></summary></entry><entry><title type="html">高阶函数初探(四)</title><link href="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E5%9B%9B)/" rel="alternate" type="text/html" title="高阶函数初探(四)" /><published>2018-11-07T13:50:07-08:00</published><updated>2018-11-07T13:50:07-08:00</updated><id>https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E5%9B%9B)</id><content type="html" xml:base="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E5%9B%9B)/"><![CDATA[<p>这周主要将上周讨论的方法实现了，并将十个项目进行了详细的统计，得到了第一版的数据，从数据中我们或许能看到一点东西。</p>

<!--more-->

<h2 id="主要工作">主要工作</h2>

<p>上周主要做了三个工作：</p>

<ul>
  <li>完善提取调用关系的代码</li>
  <li>将每个函数声明和调用都与相应的作者进行匹配</li>
  <li>统计了第一版较为完善的信息</li>
</ul>

<h3 id="提取调用关系">提取调用关系</h3>

<p>按照之前讨论的思路，首先遍历项目，提取所有的函数声明的信息，并保存函数的类名，方法名，参数的数量和函数参数的位置，然后再遍历一遍项目，提取每一个函数调用，并根据之前提取的信息进行匹配函数的声明，通过一次又一次的修改测试，整出来一个尚可的版本。<br />
提取函数调用并保存到数据库，便于快速查询。<br />
<img src="/images/176.png" alt="图片描述" /><br />
但是，提取调用关系仍然存在以下问题(每跑一个项目都会发现相应的问题，修改完以后还要重新跑一遍之前的项目，心累)。</p>

<ul>
  <li>如果高阶函数在声明的时候存在默认值，在函数调用时无法根据参数来判断是否为高阶函数调用。   <img src="/images/177.png" alt="图片描述" /></li>
  <li>创建新的对象的时候没有用<code class="language-plaintext highlighter-rouge">new</code>关键字，因为在匹配函数调用时，我需要知道这个调用具体属于哪个对象，属于哪个类，我将一个文件中的所有new出来的对象存在一个symbol表中，但是没有关键字<code class="language-plaintext highlighter-rouge">new</code>不容易识别：<br />
<img src="/images/179.png" alt="图片描述" /></li>
  <li>一些非常奇怪的调用：<br />
<img src="/images/180.png" alt="图片描述" /> <br />
<img src="/images/178.png" alt="图片描述" /></li>
  <li>一些高阶函数十分相似的：<br />
<img src="/images/181.png" alt="图片描述" /></li>
  <li>嵌套函数，有些高阶函数嵌套在一些函数里面，按照常理这些函数并不属于某些class或者object,只能在所嵌套的函数内使用，所以这些嵌套函数并没有统计。<br />
<img src="/images/182.png" alt="图片描述" /></li>
</ul>

<p>除了上面的问题，提取的函数调用基本没有什么问题，还有就是在函数调用类型判断的时候，类型一的数量实际上会比实际上多，因为里面会包含那种从上层函数直接继承来的函数。因为在判断类型的时候，类型一是处于逻辑上的else语句上。
<img src="/images/159.png" alt="图片描述" /></p>

<h2 id="作者匹配">作者匹配</h2>

<p>上周解决了提取git log困难的信息，采用了将其存入数据库的方法，现在派上了用场了，我的思路是根据函数所在文件的路径以及函数的第一行来进行匹配。 <br />
<img src="/images/183.png" alt="图片描述" /><br />
但是其中也存在一些问题，95%以上的作者都能找到，另有一些函数没有找到作者，最后通过发现，函数第一行都能匹配到，但是路径总是不对，最后通过观察发现，有些文件或者变换了路径或者修改了文件名称导致在log文件中没有找到，最后只能通过手动将剩余没有找的信息补充完整。<br />
<img src="/images/184.png" alt="图片描述" /></p>

<h2 id="最终的统计结果">最终的统计结果</h2>

<p>详细的信息(每个函数声明和调用的信息)sql文件已上传，最终的简略表格统计在这里列出。</p>

<ul>
  <li>基本信息<br />
<img src="/images/185.png" alt="图片描述" /></li>
  <li>高阶函数声明代码行数信息 
<img src="/images/186.png" alt="图片描述" /></li>
  <li>高阶函数声明类型信息<br />
<img src="/images/187.png" alt="图片描述" /></li>
  <li>高阶函数调用类型信息<br />
<img src="/images/188.png" alt="图片描述" /></li>
  <li>高阶函数声明调用作者信息<br />
<img src="/images/189.png" alt="图片描述" /></li>
</ul>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="高阶函数" /><category term="scala" /><category term="高阶函数" /><summary type="html"><![CDATA[这周主要将上周讨论的方法实现了，并将十个项目进行了详细的统计，得到了第一版的数据，从数据中我们或许能看到一点东西。]]></summary></entry><entry><title type="html">高阶函数初探(三)</title><link href="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E4%B8%89)/" rel="alternate" type="text/html" title="高阶函数初探(三)" /><published>2018-10-25T11:36:11-07:00</published><updated>2018-10-25T11:36:11-07:00</updated><id>https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E4%B8%89)</id><content type="html" xml:base="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E4%B8%89)/"><![CDATA[<p>本周主要继续之前设计的实验，本打算在一个星期内做完所有实验，结果发现里面有很多问题。</p>

<!--more-->

<h2 id="main-work-上周完成的主要工作">Main Work (上周完成的主要工作)</h2>

<p>上周主要按照之前的实验设计统计数据。统计的数据主要有：</p>

<ul>
  <li>高阶函数的数量，声明类型数量：
    <ul>
      <li>类型一：仅参数包含函数：<br />
  <img src="/images/162.png" alt="图片描述" /></li>
      <li>类型二：仅返回函数：<br />
  <img src="/images/163.png" alt="图片描述" /></li>
      <li>类型三：both:<br />
  <img src="/images/164.png" alt="图片描述" /></li>
      <li>统计结果：<br />
  <img src="/images/165.png" alt="图片描述" /></li>
    </ul>
  </li>
  <li>高阶函数的行数：
    <ul>
      <li>分为0-10,10-20,20-30,30-四种类型，统计结果：<br />
  <img src="/images/166.png" alt="图片描述" /></li>
    </ul>
  </li>
  <li>高阶函数调用类型：
    <ul>
      <li>类型一：参数为函数，其中函数来自本类内新建的函数：<br />
  <img src="/images/155.png" alt="图片描述" /></li>
      <li>类型二：参数为函数，函数为匿名函数，lambda函数，写在方法调用体中：<br />
  <img src="/images/156.png" alt="图片描述" /></li>
      <li>类型三：参数为函数，函数是传入对象的一个属性：<br />
  <img src="/images/158.png" alt="图片描述" /></li>
      <li>类型四：无参数，函数声明是仅返回函数：<br />
  <img src="/images/167.png" alt="图片描述" /></li>
      <li>统计结果：<br />
  <img src="/images/168.png" alt="图片描述" /></li>
    </ul>
  </li>
  <li>高阶函数声明调用作者：
    <ul>
      <li>git log 文件：<br />
  <img src="/images/169.png" alt="图片描述" /></li>
      <li>根据log文件，函数路径，函数名查找作者，程序截图：<br />
  <img src="/images/170.png" alt="图片描述" /></li>
      <li>统计结果(未统计完）：
  <img src="/images/171.png" alt="图片描述" /></li>
    </ul>
  </li>
  <li>高阶函数嵌套高阶函数的例子：
    <ul>
      <li><img src="/images/167.png" alt="图片描述" /></li>
      <li><img src="/images/172.png" alt="图片描述" /><br />
<img src="/images/173.png" alt="图片描述" /></li>
    </ul>
  </li>
  <li>高阶函数模板使用数量：
    <ul>
      <li>模板函数：<br />
   <img src="/images/174.png" alt="图片描述" /></li>
      <li>统计结果(暂未统计)</li>
    </ul>
  </li>
</ul>

<h2 id="遇到的问题">遇到的问题</h2>

<ul>
  <li>scala meta 无法提取出函数调用，scala meta提供了相关的工具 SemanticDB，顾名思义语义数据库，也就是在程序编译的时候将各种方法符号写进他自己定义的数据库中，但是针对一些简单的程序，加了这个组件是没问题，但是针对一些较大的程序，加了组件编译不通过，无法得到数据库。 https://scalameta.org/docs/semanticdb/guide.html <br />
还有就是前两天，看之前写的异常处理的程序的时候，还可以利用jar包来解析调用关系，但是还没有尝试，我在提取作者的时候需要文件路径和方法名，不知最后能不能提供出来。还有就是我觉得除了前三个项目的scala项目高阶函数较多，其他的项目相对较少，手动统计工作量也不是很巨大，我一般就是将项目导入Idea，然后find usage查找调用。<br />
 <img src="/images/175.png" alt="图片描述" /></li>
  <li>遇到的第二个问题就是提取作者的时候，我的思路是通过<code class="language-plaintext highlighter-rouge">git log -p&gt; **.txt</code>的命令首先将所有的commit的信息生成文件，然后对文件中的字符串进行切割，预处理，搜索，查找我们制定的作者，但是有时候这个文件又特别大，很占内存，读的时候很慢，实验也就卡在这里了，我也尝试了其他读取文件的方法，效果不是很好，另外，java提供了jGit这个工具，可以允许你用java代码调用git接口，但是我找到了git.log()这个api,但是得到的东西很少，没有包含每次提交添加了什么代码，也就是没有命令行里面<code class="language-plaintext highlighter-rouge">-p</code>的选项。</li>
</ul>

<h2 id="下周的工作">下周的工作</h2>

<p>针对上面的问题，继续寻找解决方法，增加项目数量，继续统计数据。</p>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="高阶函数" /><category term="scala" /><category term="高阶函数" /><summary type="html"><![CDATA[本周主要继续之前设计的实验，本打算在一个星期内做完所有实验，结果发现里面有很多问题。]]></summary></entry><entry><title type="html">高阶函数初探(二)</title><link href="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E4%BA%8C)/" rel="alternate" type="text/html" title="高阶函数初探(二)" /><published>2018-10-06T12:24:03-07:00</published><updated>2018-10-06T12:24:03-07:00</updated><id>https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E4%BA%8C)</id><content type="html" xml:base="https://xuyisen.github.io/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0/%E9%AB%98%E9%98%B6%E5%87%BD%E6%95%B0%E5%88%9D%E6%8E%A2(%E4%BA%8C)/"><![CDATA[<p>本周由于雅思笔试，口试延误了很长时间，所以实验做的比较晚。这周主要完成了对scala的一个项目项目的详细统计，统计结果包括高阶函数声明数，高阶函数调用数，以及这两者有什么关系；scala文档对高阶函数的定义；统计泛化功能高阶函数；最后自己总结了一点高阶函数的特点。</p>

<!--more-->

<h2 id="高阶函数声明与调用">高阶函数声明与调用</h2>

<p>上次实验我主要统计了所有的scala项目的高阶函数声明的数量，并没有对其调用进行统计，而且后来才发现我只统计了那些函数行数大于10行的函数，所以这次实验要重新进行统计。<br />
这次实验选取的项目为跑<code class="language-plaintext highlighter-rouge">playframework</code>: <br />
<code class="language-plaintext highlighter-rouge">playframework</code>是一个full-stack（全栈的） Web的应用框架，包括一个简单的无状态MVC模型，具有Hibernate的对象持续，一个基于Groovy的模板引擎，以及建立一个现代Web应用所需的所有东西。而且<code class="language-plaintext highlighter-rouge">playframework</code>是star最多的一个scala项目。 <br />
实验步骤：</p>

<ul>
  <li>提取数据：在提取数据的过程中发现，函数声明可以利用代码快速提取出来，但是函数调用并不能利用之前的工具提取，因为scalameta并不能像java中的JDT那样对整个项目进行分析，只能每次对一个文件进行解析，只是分析函数中的词法和语法，并不能分析出来函数调用这种语义信息，所以我就手动统计了每个函数的调用关系。方法是提取所有的函数，与高阶函数的名称一一对比，再进行原函数一一查看。</li>
  <li>统计数据：在提取完函数声明和函数调用数据后，我对这些数据进行了简单的统计： <br />
<img src="/images/139.png" alt="图片描述" /> <br />
<img src="/images/140.png" alt="图片描述" /><br />
这里说明一下，在统计所有的高阶函数里面，并不是所有的都能找到调用关系，而且有些函数都是一些重构或者构造函数，在这里我没有统计这些函数的调用。如：  <br />
<img src="/images/141.png" alt="图片描述" /><br />
像<code class="language-plaintext highlighter-rouge">apply,map</code>这样的函数，在高阶函数里面就有很多，在所有函数里面搜索关键字就有几百条。</li>
  <li>分析数据：我们已经知道了函数声明和调用具体的数量了，接下来就是统计二者到底有啥关系了：<br />
通过统计分析发现大多数高阶函数的调用和声明都在同一个文件中：<br />
<img src="/images/142.png" alt="图片描述" />
    <ul>
      <li>在一个文件中的函数调用：
  <img src="/images/143.png" alt="图片描述" /><br />
  <img src="/images/144.png" alt="图片描述" /><br />
  <img src="/images/145.png" alt="图片描述" /></li>
      <li>不在同一个文件<br />
  <img src="/images/146.png" alt="图片描述" /><br />
  <img src="/images/147.png" alt="图片描述" /><br />
  <img src="/images/148.png" alt="图片描述" /><br />
  <img src="/images/149.png" alt="图片描述" /></li>
    </ul>
  </li>
</ul>

<h2 id="高阶函数声明调用作者分析">高阶函数声明&amp;调用作者分析</h2>

<p>前面我们统计了一个项目中的高阶函数的分布，发现大多数函数声明和调用都发生在同一个文件中，所以我就打算统计一下那些没有在同一个文件中的高阶函数的声明和调用是不是同一个作者。<br />
所有的作者信息：<br />
<img src="/images/150.png" alt="图片描述" /><br />
最先创建文件作者信息： <br />
<img src="/images/151.png" alt="图片描述" /> <br />
只有三对的初始化作者是相同的，其余作者都不相同。</p>

<h2 id="scala-文档中有关高阶函数的解释">scala 文档中有关高阶函数的解释</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Higher order functions take other functions as parameters or return a function as a result. This is possible because functions are first-class values in Scala. The terminology can get a bit confusing at this point, and we use the phrase “higher order function” for both methods and functions that take functions as parameters or that return a function.
</code></pre></div></div>
<p>也就是之前我们说的高阶函数的定义，没有说明为什么要用高阶函数。 <br />
但在另一个scala-exercise网站上举了一个例子：https://www.scala-exercises.org/scala_tutorial/higher_order_functions</p>

<p><img src="/images/152.png" alt="图片描述" /><br />
<img src="/images/153.png" alt="图片描述" /><br />
<img src="/images/153.png" alt="图片描述" /></p>

<p>总结：使用高阶函数可以减少代码，尤其是在比较复杂的流程中，这类似于Strategy模式，将核心算法整体替换，整个架构不变，比如一个有不同水平的棋类游戏，高阶函数的让这个实现更简单。</p>

<h2 id="scala-高阶函数调用">scala 高阶函数调用</h2>

<p>调用函数的类型：</p>
<ul>
  <li>函数参数就在高阶函数附近： <br />
<img src="/images/155.png" alt="图片描述" /></li>
  <li>函数参数就在函数调用中编写：<br />
<img src="/images/156.png" alt="图片描述" /><br />
<img src="/images/157.png" alt="图片描述" /></li>
  <li>函数参数来自上一级函数的参数<br />
<img src="/images/159.png" alt="图片描述" /><br />
<img src="/images/160.png" alt="图片描述" /></li>
  <li>函数参数是对象的一个方法<br />
<img src="/images/158.png" alt="图片描述" /></li>
</ul>

<p>经过我粗略的统计，发现上面四中使用方法中，第一种使用的最少，使用最多的是第三种和第四种，函数参数就在函数调用中编写的情况处于两者之间，但是比第一种多很多。</p>

<h2 id="高阶函数的泛化">高阶函数的泛化</h2>

<p>之前所说的高阶函数的主要目的就是简化代码，然后抽象化。在项目统计高阶函数数据时，我发现很多高阶函数在参数面前都有一个[T],这根我们之前c++中的template<T>的功能相同，提供模板。  
![图片描述](/images/161.png)</T></p>

<p>而且在所统计的数据中，模板高阶函数还占有很大的比重，在我提取的166个高阶函数中，有97个加了模板[T]。</p>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="高阶函数" /><category term="scala" /><category term="高阶函数" /><summary type="html"><![CDATA[本周由于雅思笔试，口试延误了很长时间，所以实验做的比较晚。这周主要完成了对scala的一个项目项目的详细统计，统计结果包括高阶函数声明数，高阶函数调用数，以及这两者有什么关系；scala文档对高阶函数的定义；统计泛化功能高阶函数；最后自己总结了一点高阶函数的特点。]]></summary></entry><entry><title type="html">简单代码克隆检测(经验性分析初版)</title><link href="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E4%BB%A3%E7%A0%81%E5%85%8B%E9%9A%86%E6%A3%80%E6%B5%8B(%E7%BB%8F%E9%AA%8C%E6%80%A7%E5%88%86%E6%9E%90%E5%88%9D%E7%89%88)/" rel="alternate" type="text/html" title="简单代码克隆检测(经验性分析初版)" /><published>2018-09-17T07:38:24-07:00</published><updated>2018-09-17T07:38:24-07:00</updated><id>https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E4%BB%A3%E7%A0%81%E5%85%8B%E9%9A%86%E6%A3%80%E6%B5%8B(%E7%BB%8F%E9%AA%8C%E6%80%A7%E5%88%86%E6%9E%90%E5%88%9D%E7%89%88)</id><content type="html" xml:base="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E4%BB%A3%E7%A0%81%E5%85%8B%E9%9A%86%E6%A3%80%E6%B5%8B(%E7%BB%8F%E9%AA%8C%E6%80%A7%E5%88%86%E6%9E%90%E5%88%9D%E7%89%88)/"><![CDATA[<p>这周主要按照上次开会的内容作了两个实验，第一个是统计20个github上star最多的scala项目中高阶函数的使用情况，第二个是借助github api 查看高阶函数所在文件的创建和修改的人时候固定。</p>

<!--more-->

<h2 id="提取高阶函数">提取高阶函数</h2>

<p>这一步就是在之前构造AST的代码上做进一步进行修改。之前博客中提到高阶函数的定义： <br />
满足以下条件之一：</p>
<ul>
  <li>接受一个或多个函数作为输入</li>
  <li>输出一个函数</li>
</ul>

<p>就是高阶函数：</p>

<p>但是由于scala 函数默认最后一句话为返回值，且利用工具scala-mate查看不出最后一句话的类型，所以我只能从传入的是个函数这个判断条件来进行提取数据。<br />
高阶函数示例：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def sum(f:Int=&gt;Int):(Int,Int)=&gt;Int={
       def sumF(a:Int,b:Int):Int=
         if(a&gt;b) 0
         else f(a)+sumF(a+1,b)
       sumF
   }
</code></pre></div></div>
<p>构造的AST树： <br />
<img src="/images/133.png" alt="图片描述" /></p>

<p>所以只要判断函数的参数里面有函数的类型即<code class="language-plaintext highlighter-rouge">Type.Function</code>即可，所以修改后的代码如下：<br />
<img src="/images/134.png" alt="图片描述" /><br />
20个项目选取的网址：<br />
https://github.com/search?l=Scala&amp;o=desc&amp;p=1&amp;q=scala&amp;s=stars&amp;type=Repositories<br />
接下来就是git clone 20个项目，跑实验，统计每个项目中高阶函数的个数，统计结果如下：</p>

<p><img src="/images/135.png" alt="图片描述" /></p>

<p>通过观察实验结果可以发现，高阶函数占比并不是很高，除了<code class="language-plaintext highlighter-rouge">fpinscala</code>,<code class="language-plaintext highlighter-rouge">scalaz</code>,<code class="language-plaintext highlighter-rouge">sbt</code> 三个项目占比较高外，其他项目都低于10%。说明高阶函数的普及型并不是很高。</p>

<h2 id="获取commit信息">获取commit信息</h2>

<p>通过github api 获取文件的commit信息，很简单，就直接写了一个python 函数，统计了每个项目每个高阶函数所在文件的commit的历史作者和最早提交的作者。</p>

<p>提取函数的代码链接：https://gitee.com/iss2015302580249/scalaCommitInfo</p>

<p>在提取commit的信息的时候遇到了一个问题，就是提取账户名的时候，会有不存在的现象，也就是  <code class="language-plaintext highlighter-rouge">login</code>字段为空，我感觉应该是账户已经注销了，所以我提取的是commit里面的<code class="language-plaintext highlighter-rouge">author</code>字段的信息，也就是用户姓名的信息。</p>

<p><img src="/images/136.png" alt="图片描述" /></p>

<p>最终的统计结果： <br />
<img src="/images/137.png" alt="图片描述" /></p>

<p>通过实验结果我们可以看出，高阶函数所在文件创始者总数占比也很低，但是我们不能确定，文件的创始者就是高阶函数的创始者，这一点有待讨论和解决：</p>

<p><code class="language-plaintext highlighter-rouge">实验最终数据链接</code>：https://gitee.com/iss2015302580249/scala_data</p>

<p><img src="/images/138.png" alt="图片描述" /></p>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="Scala" /><category term="clone_detection" /><summary type="html"><![CDATA[这周主要按照上次开会的内容作了两个实验，第一个是统计20个github上star最多的scala项目中高阶函数的使用情况，第二个是借助github api 查看高阶函数所在文件的创建和修改的人时候固定。]]></summary></entry><entry><title type="html">简单代码克隆检测(程序优化，GPU版本代码的修改)</title><link href="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E4%BB%A3%E7%A0%81%E5%85%8B%E9%9A%86%E6%A3%80%E6%B5%8B(%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96-GPU%E7%89%88%E6%9C%AC%E4%BB%A3%E7%A0%81%E7%9A%84%E4%BF%AE%E6%94%B9)/" rel="alternate" type="text/html" title="简单代码克隆检测(程序优化，GPU版本代码的修改)" /><published>2018-09-07T08:35:04-07:00</published><updated>2018-09-07T08:35:04-07:00</updated><id>https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E4%BB%A3%E7%A0%81%E5%85%8B%E9%9A%86%E6%A3%80%E6%B5%8B(%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96%EF%BC%8CGPU%E7%89%88%E6%9C%AC%E4%BB%A3%E7%A0%81%E7%9A%84%E4%BF%AE%E6%94%B9)</id><content type="html" xml:base="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E4%BB%A3%E7%A0%81%E5%85%8B%E9%9A%86%E6%A3%80%E6%B5%8B(%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96-GPU%E7%89%88%E6%9C%AC%E4%BB%A3%E7%A0%81%E7%9A%84%E4%BF%AE%E6%94%B9)/"><![CDATA[<p>本周的主要任务是对现有版本的代码进行优化，并通过修改程序代码产生GPU版本的代码，经过试验发现，提速的效果尚可，但不是很明显。</p>

<!--more-->

<h2 id="程序优化背景">程序优化背景</h2>

<p>通过之前的实验我们可以发现，程序运行的时间主要发生在<code class="language-plaintext highlighter-rouge">autoencoder</code>上面，即将词向量转换成句向量的过程。对此我想根据网上的一些方法对这部分代码进行优化，其优化的方法主要有以下几个过程。</p>

<h3 id="多进程执行">多进程执行</h3>

<p>在上次开会的时候我们就已经说了，代码已经使用openmpi允许我们多进程并行计算，于是我就简单的测试了多个进程和单个进程执行的时间差异。</p>

<ul>
  <li>
    <p>2个进程，CPU<br />
我是在李老师提供的GPU服务器上跑的实验，该实验并没有调用GPU进行加速。<br />
启动 <br />
<img src="/images/115.png" alt="图片描述" /><br />
开启的两个进程<br />
<img src="/images/116.png" alt="图片描述" /><br />
未调用GPU <br />
<img src="/images/117.png" alt="图片描述" /><br />
结果： 跑了80分钟，没跑完，我强行结束了 <br />
<img src="/images/118.png" alt="图片描述" /></p>
  </li>
  <li>
    <p>10个进程，CPU<br />
同样是在相同的服务器上进行的实验，该实验并没有调用GPU进行加速 <br />
启动<br />
<img src="/images/119.png" alt="图片描述" /><br />
开启10个进程<br />
<img src="/images/120.png" alt="图片描述" /><br />
未调用GPU<br />
结果：  1991s<br />
<img src="/images/121.png" alt="图片描述" /></p>
  </li>
  <li>
    <p>20个进程，CPU<br />
启动<br />
<img src="/images/122.png" alt="图片描述" /><br />
开启20个进程<br />
<img src="/images/123.png" alt="图片描述" /><br />
未调用GPU<br />
结果： 1847s <br />
<img src="/images/124.png" alt="图片描述" /></p>
  </li>
</ul>

<p>通过实验可以看出来之后简单的增加的运行的进程已经对速度的提升不太明显，所以之后祭出神器GPU来对我们的代码进行加速。</p>

<h3 id="gpu代码加速">GPU代码加速</h3>

<p>通过阅读代码发现，该<code class="language-plaintext highlighter-rouge">autoencoder</code>使用的是Numpy,Scipy来进行的系列的矩阵操作，并没有使用什么TensorFlow类似的神经网络框架，所以并没有现成的GPU版本的框架直接替代，到目前为止有两个方法，一个是将Scipy转为用TensorFlow类似神经网络的框架，但是没有任何实践经验，无从下手，所以我决定在代码内部做点改变，使其支持GPU。具体尝试的方法有以下几种：</p>

<ul>
  <li>minpy:  http://www.yueye.org/2017/use-minpy-to-accelerate-numpy.html  ,使用minpy替代Numpy进行矩阵操作，经过试验发现失败了，原因是，minpy只实现了Numpy的部分功能，许多方法并不能支持。</li>
  <li>Numba:  http://numba.pydata.org/numba-doc/0.39.0/index.html  Numba 是通过加注释的方法直接将Python 里面的一些数组和数学操作编译为本机机器指令，性能类似与C,C++和Fortran,无需切换语言或者python编译器。说的比较神奇，通过官网的介绍感觉也很神奇，加一个注释就可以实现加速然后在GPU上跑，看一个简单的例子： <br />
<img src="/images/125.png" alt="图片描述" /> <br />
然后就做了实验，在我们代码forword的函数上面加了注释，结果报了一堆BUG,什么类型不对，不支持object类型等等，当时改了好久，实在改不下去了，就放弃。实验失败。</li>
  <li>cupy： https://cupy.chainer.org/  ，cupy 号称是 Numpy的GPU版本，在说明文档里也一直和Numpy比较，还可以实现两种结构数据的转换，做了一点简单的实验，觉得应该可以转换。</li>
</ul>

<p>所以最终决定使用cupy替代Numpy,实现GPU支持，当然其中需要修改很多代码，虽然官网说是完全替代，其实并不是。最终经过两天半的不断修改，GPU版本可以运行了，我们看下结果。</p>

<ul>
  <li>
    <p>4 个进程 GPU<br />
还是使用李老师给的GPU服务器 <br />
启动<br />
<img src="/images/126.png" alt="图片描述" /> <br />
调用GPU<br />
<img src="/images/128.png" alt="图片描述" /> <br />
结果：  1578s<br />
<img src="/images/131.png" alt="图片描述" /> <br />
这里我们只是用了服务器里面的一块GPU，并没有全部使用，结果看来虽然加速了，但是效果并不是很好啊，就提高了300s,当时我怀疑是服务器配置的问题，以为我开启四个进程，GPU就100%了，所以我决定在贾老师的电脑里试一试。于是又花了一天的时间配置服务器的环境，进行了实验。实验结果如下。</p>
  </li>
  <li>
    <p>10个进程 GPU<br />
使用的是贾老师实验室的服务器 <br />
启动<br />
<img src="/images/129.png" alt="图片描述" /> <br />
调用GPU <br />
<img src="/images/130.png" alt="图片描述" /><br />
结果  ：  909s <br />
<img src="/images/132.png" alt="图片描述" /><br />
这次实验也只用电脑里面的一块GPU，速度提升可以看到，一半左右，但是也没有达到10倍一百倍那种地步，后期还需要探索问一下相关老师。</p>
  </li>
</ul>

<p>Note: GPU 版本相关代码已经发布到 GitLab上面去了:   http://125.220.157.228/clone_detection/clone_detection_tools_gpu   ，老师可以进行相关测试。</p>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="Scala" /><category term="clone_detection" /><summary type="html"><![CDATA[本周的主要任务是对现有版本的代码进行优化，并通过修改程序代码产生GPU版本的代码，经过试验发现，提速的效果尚可，但不是很明显。]]></summary></entry><entry><title type="html">简单克隆代码检测(Scala函数式编程初探)</title><link href="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E5%85%8B%E9%9A%86%E4%BB%A3%E7%A0%81%E6%A3%80%E6%B5%8B(Scala%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%88%9D%E6%8E%A2)/" rel="alternate" type="text/html" title="简单克隆代码检测(Scala函数式编程初探)" /><published>2018-08-30T02:44:56-07:00</published><updated>2018-08-30T02:44:56-07:00</updated><id>https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E5%85%8B%E9%9A%86%E4%BB%A3%E7%A0%81%E6%A3%80%E6%B5%8B(Scala%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%88%9D%E6%8E%A2)</id><content type="html" xml:base="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E5%85%8B%E9%9A%86%E4%BB%A3%E7%A0%81%E6%A3%80%E6%B5%8B(Scala%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E5%88%9D%E6%8E%A2)/"><![CDATA[<p>函数式编程又称泛函编程的一种编程泛型，他将计算机运算视为数学上的函数计算，并且避免使用程序状态以及易变对象。函数编程语言最重要的基础是lambda演算。</p>

<!--more-->

<h1 id="命令式编程lmperative">命令式编程(lmperative)</h1>

<p>命令”机器”如何去做事情，这样不管你想要的是什么，他都会按照你的命令实现。</p>

<h1 id="函数式编程functional">函数式编程(functional)</h1>

<p>告诉”机器”你想要什么，让机器想出如何去做</p>

<h1 id="example">Example</h1>

<ul>
  <li>Java Code \lmperative
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Integer[] nums = new Integer[]{1, 2, 3, 4};
int i=0;
for (Integer n : nums) {
  n*=2;
  nums[i++]=n;
}
</code></pre></div>    </div>
    <p>遍历整个数组，取出每个元素，乘以二，然后把翻倍后的值放回数组，每次都要操作这个数组，直到计算完所有元素。</p>
  </li>
  <li>Scala code \ functional
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val nums = Array(1,2,3,4)
val doubleNums = nums.map(_*2)
</code></pre></div>    </div>
    <p>利用Array的map函数，将所有元素<em>2，并生成了一个新的双倍数组。map函数所做的事情是把遍历整个数组的过程，归纳并抽离出来，让我们专注于描述我们想要的是什么”_</em>2”。我们传入map的是一个纯函数；它不具有任何副作用(不会改变外部状态)，它只是接收一个数字，返回乘以二后的值。PS： ‘_’ 字符是scala中的入参缩写形式。</p>
  </li>
</ul>

<h1 id="普通函数">普通函数</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def max(x: Int, y: Int): Int = {
  if (x &gt; y) x else y
}
</code></pre></div></div>
<p>def 是声明函数的关键字，小括号中的x:Int,y:int是函数的入参，紧跟着的:Int是函数返回值类型，花括号中的是函数体。</p>

<h1 id="匿名函数">匿名函数</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val increment = (x: Int) =&gt; x + 1
increment(2)
// output 3 
</code></pre></div></div>
<p>匿名函数是指一类无需定义标识符的函数，定义匿名函数的语法很简单，=&gt;箭头左边是参数列表，右边是函数体。可以把命名函数赋值给一个变量使用。<br />
另一种方式</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val increment =new Function1[Int, Int] {
  def apply(x: Int): Int = x + 1
}
</code></pre></div></div>

<h1 id="无参匿名函数">无参匿名函数</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val sayHello = () =&gt; { System.out.print("Hello World!") }
sayHello()
//output: Hello World!
</code></pre></div></div>

<h1 id="高阶函数">高阶函数</h1>

<p>满足以下条件之一：</p>
<ul>
  <li>接受一个或多个函数作为输入</li>
  <li>输出一个函数</li>
</ul>

<p>在数学领域他们也叫做算子或泛函。微积分中的导数就是常见的例子，它映射一个函数到另一个函数。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val convert2String=(x:Int)=&gt;"==[" + x.toString() + "]=="
def apply(f: Int =&gt; String, v: Int) = f(v)
apply(convert2String,36)
//output: ==[36]==
</code></pre></div></div>

<h1 id="嵌入式函数本地函数">嵌入式函数(本地函数)</h1>

<p>在Scala中可以在函数体中再定义一个函数。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def filter(xs: List[Int], threshold: Int) = {
    def process(ys: List[Int]): List[Int] =
    if (ys.isEmpty) ys
    else if (ys.head &lt; threshold) ys.head :: process(ys.tail)
    else process(ys.tail)
    process(xs)
}
</code></pre></div></div>

<h1 id="函数柯里化currying">函数柯里化(Currying)</h1>

<p>在计算机科学中，柯里化是指把接受多个参数的函数变换成接受一个单一参数的函数，并且返回其余的参数和结果的函数。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def curriedSum(x: Int)(y: Int)(z: Int) = x + y + z
val sum = curriedSum(1)(2)(3)
//output: 6

//the calling procedure of currying function
def first(x: Int) = (y: Int) =&gt; (z: Int) =&gt; x + y + z
def second = first(5)
//output: Int =&gt; (Int =&gt; Int) = 5 + y + z
def third = second(6)
//output: Int =&gt; Int = 5 + 6 + z
val fourth = third(7)
//output: 18

first(5)(6)(7)
//output: 18
</code></pre></div></div>
<p>代码范例中，curriedSum是一个currying函数的Scala写法，而first、second、third、fourth展示了currying函数调用过程。通过代码注释可看到second、third返回的都是函数，直到fourth才返回求和值。而这种特性也正是惰性求值的秘密所在。</p>

<h1 id="部分应用函数">部分应用函数</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def sum(x: Int, y: Int, z: Int) = {
x + y + z
}
val sum2 = sum(10, _: Int, 15)
sum2(2)
//output: 27
</code></pre></div></div>

<h1 id="偏函数">偏函数</h1>

<h2 id="定义">定义</h2>

<p>从输入集合X到可能的输出集合Y的函数f(记作f(X)=&gt;Y)是X与Y的关系，满足如下条件：</p>
<ol>
  <li>f是完全的即对于集合X中的任一元素x都有集合Y中的元素y，从而满足f(x)=y,换句话说就是每一个输入值x都有y与之对应。</li>
  <li>f是多对一的即存在 f(x_{a})=y且f(x_{b})=z并且y=z。也就是多个输入可以映射一个输出，但一个输入不能映射多个输出</li>
</ol>

<p>X与Y的关系f满足条件1，则为<code class="language-plaintext highlighter-rouge">多值函数</code>。X与Y的关系f满足条件2，则为<code class="language-plaintext highlighter-rouge">偏函数</code>。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val pf: PartialFunction[Int, String] = {
  case 1 =&gt; "One"
  case 2 =&gt; "Two"
  case 3 =&gt; "Three"
  case 9 =&gt; "Nine"
  case _=&gt; "Nothing"
}
pf(1) // output: One
pf(2) // output: Two
pf(5) // output: Nothing
pf(9) // output: Nine
</code></pre></div></div>
<p>示例代码中，我们定义了一个Scala的偏函数，那么只有1、2、3、9有对应的输出值，而输入其它值只会打印 Nothing。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val L1 = List(1, 2, 3, "A", 4, "B", 5)
val L2 = L1 map { 
case x: Int =&gt; x * x
case x: String =&gt; s"$x*$x"
}
//L2: List[Any] = List(1, 4, 9, A*A, 16, B*B, 25)
</code></pre></div></div>

<h1 id="闭包">闭包</h1>

<p>又称函数闭包，是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在，换句话说，闭包是由函数和与其相关的引用环境组合成的。  <br />
另外一种解释，对象是带有函数的数据，闭包是带有数据的函数。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>val more = 2
val addMore = (x: Int) =&gt;  x + more
addMore(1)
</code></pre></div></div>

<h1 id="传值调用函数call-by-value">传值调用函数(call by value)</h1>

<p>将未计算的参数表达式直接应用到函数内部即为传名调用。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def assert(predicate: =&gt; Boolean) =
if (!predicate)
throw new AssertionError
assert(1 &gt; 3)
def compare(x: Int, y: Int): Boolean = {
if (x &gt; y) true else false
}
assert(compare(1, 3))
</code></pre></div></div>

<h1 id="可变参数">可变参数</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def echo(args:String*)={
for(arg &lt;- args) println(arg)
}
echo("Hello","World","!")
//output: Hello World!
</code></pre></div></div>

<h1 id="管道pipeline函数">管道(pipeline)函数</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def even(x:Array[Int]):Array[Int]={
  x.filter(_%2==0)
}
def square(x:Array[Int]):Array[Int]={
  x.map(e=&gt;e*e)
}
def total(x:Array[Int]):Int={
  x.reduce(_+_)
}
val nums = Array(1,2,3,4,5,6,7,8,9,10)
val pipeline = total(square(even(nums)))
//output: 220
</code></pre></div></div>

<h1 id="递归函数">递归函数</h1>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def fun(i:Int):Unit=
{
if (i &lt; 10 &amp;&amp; i &gt;= 0)
  {
println(s"i:$i");
    fun(i + 1);
  }
}
fun(1)
</code></pre></div></div>
<p>Scala编译器优化了尾递归调用，递归调用和执行一个while循环没有性能上区别。</p>

<h1 id="方法与函数">方法与函数</h1>

<p>在Scala中函数如果是某个对象的成员，那么称这种<code class="language-plaintext highlighter-rouge">函数</code>为<code class="language-plaintext highlighter-rouge">方法</code>。</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Sample{
def sayHello():Unit={
print("Hello")
  }
}
</code></pre></div></div>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="Scala" /><category term="clone_detection" /><summary type="html"><![CDATA[函数式编程又称泛函编程的一种编程泛型，他将计算机运算视为数学上的函数计算，并且避免使用程序状态以及易变对象。函数编程语言最重要的基础是lambda演算。]]></summary></entry><entry><title type="html">简单克隆代码检测(版本更新及相应bug修复)</title><link href="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E5%85%8B%E9%9A%86%E4%BB%A3%E7%A0%81%E6%A3%80%E6%B5%8B(%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E5%8F%8A%E7%9B%B8%E5%BA%94bug%E4%BF%AE%E5%A4%8D)/" rel="alternate" type="text/html" title="简单克隆代码检测(版本更新及相应bug修复)" /><published>2018-08-24T07:57:27-07:00</published><updated>2018-08-24T07:57:27-07:00</updated><id>https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E5%85%8B%E9%9A%86%E4%BB%A3%E7%A0%81%E6%A3%80%E6%B5%8B(%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E5%8F%8A%E7%9B%B8%E5%BA%94bug%E4%BF%AE%E5%A4%8D)</id><content type="html" xml:base="https://xuyisen.github.io/scala/%E7%AE%80%E5%8D%95%E5%85%8B%E9%9A%86%E4%BB%A3%E7%A0%81%E6%A3%80%E6%B5%8B(%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E5%8F%8A%E7%9B%B8%E5%BA%94bug%E4%BF%AE%E5%A4%8D)/"><![CDATA[<p>这一周主要对项目中代码存在的问题做了一点修改，同时想了一下如何对项目运行时间进行优化</p>

<!--more-->

<h2 id="修改的bug">修改的bug</h2>

<p>之前我们一直根据spark开源项目来开展我们的研究，没有跑其他的项目，这就造成了程序的不兼容性。果然通过英国那边的老师的反馈确实程序的健壮性出现了问题。于是又跑了几遍程序，修改出现的问题。 <br />
在修复的过程中，我们主要以scala语言的开源代码作为目标代码： https://github.com/scala/scala  ，因为我觉得这个项目应该包含了scala语言的所有特性。  最终发现了两个问题：</p>

<ul>
  <li>scala的一些语法spark项目里面并没有全部包含，这就导致了一些语法没有找到，被打印到了控制台，通过观察控制台输出的语句，在代码中添加之前未添加的语句类型即可。</li>
</ul>

<p><img src="/images/110.png" alt="图片描述" /> <br />
新添加的方法</p>

<ul>
  <li>嵌套函数的处理不完善，父函数包含的内容过少，导致错误分类。例如： <br />
<img src="/images/111.png" alt="图片描述" /></li>
  <li>父函数提取的数据相似，但是里面的子函数并不相似，所以我决定把子函数嵌入到父函数的数据里面 <br />
<img src="/images/112.png" alt="图片描述" /></li>
</ul>

<p>然后跑了一下scala语言的代码，统计了一下结果  <br />
<img src="/images/113.png" alt="图片描述" /> <br />
<img src="/images/114.png" alt="图片描述" /></p>

<h2 id="最新的项目地址">最新的项目地址</h2>

<ul>
  <li>整合工具：  http://125.220.157.228/xuyisen/clone_detection_tools</li>
  <li>scala parser:  http://125.220.157.228/clone_detection/clone_detector</li>
  <li>历史数据： https://pan.baidu.com/s/1s__XBJyCm2fXlcEP0ae1WQ</li>
</ul>

<h2 id="项目的运行时间优化">项目的运行时间优化</h2>

<p>其中可以进行分批次优化的关键步骤就是在词向量转化为句向量的过程中，目前可以采用的方法就是多个电脑并行运行这一步骤，然后将结果汇总统计距离，也可以启用多进程或者线程。</p>]]></content><author><name>Yisen Xu</name><email>yisen.xu@mail.concordia.ca</email><uri>https://petertsehsun.github.io/</uri></author><category term="Scala" /><category term="clone_dectection" /><summary type="html"><![CDATA[这一周主要对项目中代码存在的问题做了一点修改，同时想了一下如何对项目运行时间进行优化]]></summary></entry></feed>