主頁 > 軟體設計 > 是科研人就要快!加速你的演算法!

是科研人就要快!加速你的演算法!

2021-04-17 11:00:21 軟體設計

在科研中,大多數論文其實還是看精度和效果的,對于速度其實沒有那么高的追求,很多人用速度評價自己演算法的復雜度很低,但實際上這是不準確的,當然在精度占優的情況下,能夠提高速度,給自己的實驗結果增彩,

關于演算法程式的加速,在動手前先要按照如下流程進行思考,以決定從哪里入手加速,

<style>#mermaid-svg-DXq7slWMVU0a5o8D .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-DXq7slWMVU0a5o8D .label text{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .node rect,#mermaid-svg-DXq7slWMVU0a5o8D .node circle,#mermaid-svg-DXq7slWMVU0a5o8D .node ellipse,#mermaid-svg-DXq7slWMVU0a5o8D .node polygon,#mermaid-svg-DXq7slWMVU0a5o8D .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-DXq7slWMVU0a5o8D .node .label{text-align:center;fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .node.clickable{cursor:pointer}#mermaid-svg-DXq7slWMVU0a5o8D .arrowheadPath{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-DXq7slWMVU0a5o8D .flowchart-link{stroke:#333;fill:none}#mermaid-svg-DXq7slWMVU0a5o8D .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-DXq7slWMVU0a5o8D .edgeLabel rect{opacity:0.9}#mermaid-svg-DXq7slWMVU0a5o8D .edgeLabel span{color:#333}#mermaid-svg-DXq7slWMVU0a5o8D .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-DXq7slWMVU0a5o8D .cluster text{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-DXq7slWMVU0a5o8D .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-DXq7slWMVU0a5o8D text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-DXq7slWMVU0a5o8D .actor-line{stroke:grey}#mermaid-svg-DXq7slWMVU0a5o8D .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-DXq7slWMVU0a5o8D .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-DXq7slWMVU0a5o8D #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-DXq7slWMVU0a5o8D .sequenceNumber{fill:#fff}#mermaid-svg-DXq7slWMVU0a5o8D #sequencenumber{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D #crosshead path{fill:#333;stroke:#333}#mermaid-svg-DXq7slWMVU0a5o8D .messageText{fill:#333;stroke:#333}#mermaid-svg-DXq7slWMVU0a5o8D .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-DXq7slWMVU0a5o8D .labelText,#mermaid-svg-DXq7slWMVU0a5o8D .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-DXq7slWMVU0a5o8D .loopText,#mermaid-svg-DXq7slWMVU0a5o8D .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-DXq7slWMVU0a5o8D .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-DXq7slWMVU0a5o8D .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-DXq7slWMVU0a5o8D .noteText,#mermaid-svg-DXq7slWMVU0a5o8D .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-DXq7slWMVU0a5o8D .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-DXq7slWMVU0a5o8D .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-DXq7slWMVU0a5o8D .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-DXq7slWMVU0a5o8D .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .section{stroke:none;opacity:0.2}#mermaid-svg-DXq7slWMVU0a5o8D .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-DXq7slWMVU0a5o8D .section2{fill:#fff400}#mermaid-svg-DXq7slWMVU0a5o8D .section1,#mermaid-svg-DXq7slWMVU0a5o8D .section3{fill:#fff;opacity:0.2}#mermaid-svg-DXq7slWMVU0a5o8D .sectionTitle0{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .sectionTitle1{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .sectionTitle2{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .sectionTitle3{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-DXq7slWMVU0a5o8D .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .grid path{stroke-width:0}#mermaid-svg-DXq7slWMVU0a5o8D .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-DXq7slWMVU0a5o8D .task{stroke-width:2}#mermaid-svg-DXq7slWMVU0a5o8D .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .taskText:not([font-size]){font-size:11px}#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-DXq7slWMVU0a5o8D .task.clickable{cursor:pointer}#mermaid-svg-DXq7slWMVU0a5o8D .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-DXq7slWMVU0a5o8D .taskText0,#mermaid-svg-DXq7slWMVU0a5o8D .taskText1,#mermaid-svg-DXq7slWMVU0a5o8D .taskText2,#mermaid-svg-DXq7slWMVU0a5o8D .taskText3{fill:#fff}#mermaid-svg-DXq7slWMVU0a5o8D .task0,#mermaid-svg-DXq7slWMVU0a5o8D .task1,#mermaid-svg-DXq7slWMVU0a5o8D .task2,#mermaid-svg-DXq7slWMVU0a5o8D .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutside0,#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutside2{fill:#000}#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutside1,#mermaid-svg-DXq7slWMVU0a5o8D .taskTextOutside3{fill:#000}#mermaid-svg-DXq7slWMVU0a5o8D .active0,#mermaid-svg-DXq7slWMVU0a5o8D .active1,#mermaid-svg-DXq7slWMVU0a5o8D .active2,#mermaid-svg-DXq7slWMVU0a5o8D .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-DXq7slWMVU0a5o8D .activeText0,#mermaid-svg-DXq7slWMVU0a5o8D .activeText1,#mermaid-svg-DXq7slWMVU0a5o8D .activeText2,#mermaid-svg-DXq7slWMVU0a5o8D .activeText3{fill:#000 !important}#mermaid-svg-DXq7slWMVU0a5o8D .done0,#mermaid-svg-DXq7slWMVU0a5o8D .done1,#mermaid-svg-DXq7slWMVU0a5o8D .done2,#mermaid-svg-DXq7slWMVU0a5o8D .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-DXq7slWMVU0a5o8D .doneText0,#mermaid-svg-DXq7slWMVU0a5o8D .doneText1,#mermaid-svg-DXq7slWMVU0a5o8D .doneText2,#mermaid-svg-DXq7slWMVU0a5o8D .doneText3{fill:#000 !important}#mermaid-svg-DXq7slWMVU0a5o8D .crit0,#mermaid-svg-DXq7slWMVU0a5o8D .crit1,#mermaid-svg-DXq7slWMVU0a5o8D .crit2,#mermaid-svg-DXq7slWMVU0a5o8D .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-DXq7slWMVU0a5o8D .activeCrit0,#mermaid-svg-DXq7slWMVU0a5o8D .activeCrit1,#mermaid-svg-DXq7slWMVU0a5o8D .activeCrit2,#mermaid-svg-DXq7slWMVU0a5o8D .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-DXq7slWMVU0a5o8D .doneCrit0,#mermaid-svg-DXq7slWMVU0a5o8D .doneCrit1,#mermaid-svg-DXq7slWMVU0a5o8D .doneCrit2,#mermaid-svg-DXq7slWMVU0a5o8D .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-DXq7slWMVU0a5o8D .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-DXq7slWMVU0a5o8D .milestoneText{font-style:italic}#mermaid-svg-DXq7slWMVU0a5o8D .doneCritText0,#mermaid-svg-DXq7slWMVU0a5o8D .doneCritText1,#mermaid-svg-DXq7slWMVU0a5o8D .doneCritText2,#mermaid-svg-DXq7slWMVU0a5o8D .doneCritText3{fill:#000 !important}#mermaid-svg-DXq7slWMVU0a5o8D .activeCritText0,#mermaid-svg-DXq7slWMVU0a5o8D .activeCritText1,#mermaid-svg-DXq7slWMVU0a5o8D .activeCritText2,#mermaid-svg-DXq7slWMVU0a5o8D .activeCritText3{fill:#000 !important}#mermaid-svg-DXq7slWMVU0a5o8D .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-DXq7slWMVU0a5o8D g.classGroup text .title{font-weight:bolder}#mermaid-svg-DXq7slWMVU0a5o8D g.clickable{cursor:pointer}#mermaid-svg-DXq7slWMVU0a5o8D g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-DXq7slWMVU0a5o8D g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-DXq7slWMVU0a5o8D .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-DXq7slWMVU0a5o8D .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-DXq7slWMVU0a5o8D .dashed-line{stroke-dasharray:3}#mermaid-svg-DXq7slWMVU0a5o8D #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D .commit-id,#mermaid-svg-DXq7slWMVU0a5o8D .commit-msg,#mermaid-svg-DXq7slWMVU0a5o8D .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-DXq7slWMVU0a5o8D g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-DXq7slWMVU0a5o8D g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-DXq7slWMVU0a5o8D g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-DXq7slWMVU0a5o8D .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-DXq7slWMVU0a5o8D .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-DXq7slWMVU0a5o8D .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-DXq7slWMVU0a5o8D .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-DXq7slWMVU0a5o8D .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-DXq7slWMVU0a5o8D .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-DXq7slWMVU0a5o8D .edgeLabel text{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-DXq7slWMVU0a5o8D .node circle.state-start{fill:black;stroke:black}#mermaid-svg-DXq7slWMVU0a5o8D .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-DXq7slWMVU0a5o8D #statediagram-barbEnd{fill:#9370db}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-state .divider{stroke:#9370db}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-DXq7slWMVU0a5o8D .note-edge{stroke-dasharray:5}#mermaid-svg-DXq7slWMVU0a5o8D .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-DXq7slWMVU0a5o8D .error-icon{fill:#522}#mermaid-svg-DXq7slWMVU0a5o8D .error-text{fill:#522;stroke:#522}#mermaid-svg-DXq7slWMVU0a5o8D .edge-thickness-normal{stroke-width:2px}#mermaid-svg-DXq7slWMVU0a5o8D .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-DXq7slWMVU0a5o8D .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-DXq7slWMVU0a5o8D .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-DXq7slWMVU0a5o8D .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-DXq7slWMVU0a5o8D .marker{fill:#333}#mermaid-svg-DXq7slWMVU0a5o8D .marker.cross{stroke:#333} :root { --mermaid-font-family: "trebuchet ms", verdana, arial;}</style> <style>#mermaid-svg-DXq7slWMVU0a5o8D { color: rgba(0, 0, 0, 0.75); font: ; }</style>
演算法優化
語言更換
演算法并行
匯編加速
硬體加速
*光學加速
  • 演算法優化,指降低演算法計算復雜度,設計新演算法快速求解,比如Hungarian匹配演算法,或犧牲一些記憶體,預計算一些重復計算的程序,減少程式層面的復雜度,
  • 語言更換,指將自己演算法遷移到更加底層的演算法,越是低級的演算法,執行速度越快,常見地,將Matlab、Python等解釋性代碼移植到C++平臺,往往有5-20倍的加速效果,
  • 演算法并行,指將自己演算法的獨立計算部分,分成幾塊,利用CPU指令集、多核或GPU的特性實作加速,多核并行和CUDA并行最為常見,
  • 匯編加速,將自己的一片代碼指定為自己設計的匯編語言,多種C++編譯器實際上也是將語言轉換為匯編代碼,對匯編進行加速在嵌入式中常見,(該方法對平臺有需求,并不常見)
  • 硬體加速,利用特殊硬體處理特殊演算法,降低CPU架構的復雜度,常見的就是FPGA,
  • 光學加速,利用引數制作特定的光散射模型,輸入目標光源直接得到輸出結果,(離譜的加速方式,目前停留在概念

強烈注意:
所有的優化,都是在自己演算法流程不變的前提下進行優化,因為優化后的程式,高度面向程序,如果演算法某個流程要換以達到更高精度,則改動作業量較大,

下面我對每種加速方法進行詳細的說明(本文只列舉加速方法,并給出幾種參考示例,并不會詳細講解如何使用,僅介紹思想),

👇加速方法詳解

  • 1 演算法優化
  • 2 語言更換
  • 3 演算法并行
    • 3.1 指令集加速
    • 3.2 CPU 多核編程
    • 3.3 CUDA 編程加速
    • 3.4 TensorRT 加速深度學習
  • 4 匯編加速
  • 5 硬體加速
  • 6 光學加速
  • 7 總結

1 演算法優化

演算法優化分為兩種型別:① 降低演算法復雜度;② 減少重復計算程序,

  • 降低演算法復雜度,在求解最優值時候,我們最容易想到的就是暴力求解,當資料量特別大的時候,這種方法耗時就例外高,在查找、最有匹配中,有大量的優化演算法解決這類問題(圖論、資料結構、演算法導論介紹了很多方法), \newline 例如,匈牙利演算法(Hungarian Algorithm)與KM演算法(Kuhn-Munkres Algorithm)是在多目標跟蹤的論文中見到的兩種演算法,他們都是用來解決多目標跟蹤中的資料關聯問題,匈牙利演算法與KM演算法都是為了求解二分圖的最大匹配問題,下圖就是其中的二分圖,二分圖呢就是能分成兩組,U,V,其中,U上的點不能相互連通,只能連去V中的點,同理,V中的點不能相互連通,只能連去U中的點,這樣,就叫做二分圖,在影像中,可以把二分圖理解為視頻中連續兩幀中的所有檢測框,第一幀所有檢測框的集合稱為U,第二幀所有檢測框的集合稱為V,同一幀的不同檢測框不會為同一個目標,所以不需要互相關聯,相鄰兩幀的檢測框需要相互聯通,最終將相鄰兩幀的檢測框盡量完美地兩兩匹配起來,而求解這個問題的最優解就要用到匈牙利演算法或者KM演算法,
  • 減少重復計算程序,這個一般來說具體演算法具體分析,一般要么是記錄共用的中間變數,要么就是把與輸入無關的資料,在初始化變數時候計算好,簡單來說,擬合引數時候,我們經常會用到公式 A x = b Ax=b Ax=b的形式,即 x = ( A ′ A ) ? 1 A ′ b x=(A'A)^{-1}A'b x=(AA)?1Ab,這時候,定義 A = ( a 1 , a 2 , . . . , a n ) ′ A=(a_1,a_2,...,a_n)' A=(a1?,a2?,...,an?),那么 A ′ A = ∑ i = 1 n a 1 T a 1 A'A=\sum_{i=1}^na_1^Ta_1 AA=i=1n?a1T?a1?的形式,如果能預計算 a 1 T a 1 a_1^Ta_1 a1T?a1?的話,每次獲得這個矩陣經過有限次加法即可,

2 語言更換

越是高級的語言,開發效率越高,執行速度越慢

  • 盡量用當前語言的官方庫,官方庫往往對演算法做了足夠的加速,
  • 將部分簡單函式編譯成C++進行呼叫,比如Python呼叫C++,或Matlab呼叫C++,
  • 對并行性較強的,且用了少量STL庫的演算法使用CUDA加速,
  • 大矩陣運算考慮Eigen,cublas等專用庫,
  • 對并行性較強,且用了大量STL庫的演算法使用多核并行加速,
  • 將高級代碼轉換為C++專案,這也是最簡單的轉換方法了,這樣開發出的演算法非常容易落地,

3 演算法并行

并行思想從小到大可以總結為:指令集開發多核并行CUDA并行,在深度學習中,TensorRT是一種更高級的CNN網路加速方法,

3.1 指令集加速

指令集加速,一般是針對CPU架構進行的底層優化,常見于OpenCV和Tensorflow的CPU版本,之所以OpenCV是個經典的開源影像框架,很大原因是因為其在多個平臺上執行效率很高,其中底層的優化,比如指令集優化,起到了關鍵作用,

資料并行的兩種實作在計算機體系中,資料并行有兩種實作路徑:

  • MIMD(Multiple Instruction Multiple Data,多指令流多資料流),MIMD的表現形式主要有多發射、多執行緒、多核心,在當代設計的以處理能力為目標驅動的處理器中,均能看到它們的身影,
  • SIMD(Single Instruction Multiple Data,單指令流多資料流),隨著多媒體、大資料、人工智能等應用的興起,為處理器賦予SIMD處理能力變得愈發重要,因為這些應用存在大量細粒度、同質、獨立的資料操作,而SIMD天生就適合處理這些操作,SIMD本身并不是一種指令集,而是一種處理思想,現在的一些指令集都支持SIMD,(簡單來說,計算1000維向量的點積,乘法是獨立的,多核心不值得,這時候就可以利用指令集一次性計算4次或8次乘法,同樣的,之后的加法也同樣可以用指令集計算)

CPU指令集的發展(針對Intel的x86指令集系列):

  • MMX指令集 (Multi Media eXtension, 多媒體擴展指令集),MMX指令集率先在Pentium處理器中使用,MMX指令集支持算數、比較、移位等運算,MMX指令集的向量暫存器是64bit,
  • SSE指令集(Streaming SIMD Extensions,單指令多資料流擴展),所有的SSE系列指令的向量暫存器都是128bit,也就是一次性可以計算4個int,SSE最早出現在1999年,在之后的近10年內,推出了SSE,SSE2,SSE3,SSE4.1,SSE4.2,
  • AVX指令集(Advanced Vector Extensions,高級向量擴展),AVX指令集是在之前的SSE128位擴展到和256位的單指令多資料流,AVX出現在2008年,之后出了AVX2,2014年,AVX-512將資料bit由256bit擴展到了512bit,AVX是目前比較常用的指令集,256位的型別可以一次計算4個double,有效的提升性能

利用CPU-Z軟體可以查看電腦的CPU資訊,

關于指令集的使用,在博客《論文閱讀——橢圓檢測 2020:Arc Adjacency Matrix-Based Fast Ellipse Detection》給出的原始碼中,使用了AVX指令集對代碼進行處理,為了方便理解使用,我們以計算橢圓的采樣點為例,其中 x o , y o , R , r , θ x_o,y_o,R,r,\theta xo?,yo?,R,r,θ分別為橢圓的中心點、長短軸及旋轉角, c o s t , s i n t cost,sint cost,sint表示橢圓引數方程用于采樣,指令集的檔案參考Intel? C++ Compiler XE 12.1 User and Reference Guides ,

{ x = R c o s θ c o s t ? r s i n θ s i n t + x o y = R s i n θ c o s t + r c o s θ s i n t + y o \left\{\begin{array}{l}x = Rcos\theta cost-rsin\theta sint + x_o\\y = Rsin\theta cost + r cos\theta sint + y_o\end{array}\right. {x=Rcosθcost?rsinθsint+xo?y=Rsinθcost+rcosθsint+yo??

則利用指令集計算采樣點的方法如下所示,顯然原來需要計算VALIDATION_NUMBER次采樣點的程序,現在僅需要VALIDATION_NUMBER/8次(sizeof(__m256) / sizeof(float)=8),

// 初始化旋轉變換矩陣,這里angleRot = \theta
const float _ROT_TRANS[4] = { R * cos(angleRot), -r * sin(angleRot), 
	R  * sin(angleRot), r  * cos(angleRot) }; 
// Estimate the sampling points number N. Note: N = RoundEllipseCircum;
// Use SSE to faster the step of ellipse validation.

// 考慮到指令集實際上一次性計算8個資料,
// 則_mm256_set1_ps的目的是用一個float初始化一個__m256
// 舉個例子:假如需要初始化的float為k,則呼叫_mm256_set1_ps之后得到
// [k,k,k,k,k,k,k,k]
__m256 _rot_trans_0 = _mm256_set1_ps(_ROT_TRANS[0]),
	_rot_trans_1 = _mm256_set1_ps(_ROT_TRANS[1]),
	_rot_trans_2 = _mm256_set1_ps(_ROT_TRANS[2]),
	_rot_trans_3 = _mm256_set1_ps(_ROT_TRANS[3]);
	
__m256	x_center = _mm256_set1_ps(xyCenter[0]),
	y_center = _mm256_set1_ps(xyCenter[1]);

__m256 tmp_x, tmp_y, tmp_wx, tmp_wy, tmp_w;

for (int i = 0; i < VALIDATION_NUMBER; i += sizeof(__m256) / sizeof(float))
{
    // 一次性讀取256位資料,實際上就是加載8個float到base_x,base_y
    // 這里的base_x = cost, base_y = sint
	__m256 base_x = _mm256_load_ps(vldBaseDataX + i);
	__m256 base_y = _mm256_load_ps(vldBaseDataY + i);
	// calculate location x
	// _mm256_mul_ps 計算乘法:計算每個float的乘法,_mm256_add_ps 
	// 舉個例子:兩個__m256資料為[k1,k2,...,k8], [p1,p2,...,p8]
	// 呼叫_mm256_mul_ps之后,得到[k1p1,k2p2,...,k8p8]
	// 呼叫_mm256_add_ps之后,得到[k1+p1,k2+p2,...,k8+p8]
	tmp_x = _mm256_add_ps(
		_mm256_mul_ps(_rot_trans_0, base_x),
		_mm256_mul_ps(_rot_trans_1, base_y));
	tmp_x = _mm256_add_ps(tmp_x, x_center);
	// calculate location y
	tmp_y = _mm256_add_ps(
		_mm256_mul_ps(_rot_trans_2, base_x),
		_mm256_mul_ps(_rot_trans_3, base_y));
	tmp_y = _mm256_add_ps(tmp_y, y_center);

	// Save location x, y
	// _mm256_storeu_ps的目的是將計算后的8個float存入float矩陣中
	_mm256_storeu_ps(sample_x + i, tmp_x);
	_mm256_storeu_ps(sample_y + i, tmp_y);
}

其實后期測驗速度發現,實際加速效果沒有特別明顯,畢竟用了大量中間變數,且函式的呼叫傳遞了引數,指令集實際上在匯編中用的多,如果在代碼中內嵌指令集可能效果會更好,

參考資料:
1 C/C++指令集介紹以及優化(主要針對SSE優化)

3.2 CPU 多核編程

多核編程可以理解為就是多執行緒編程,總體上可以分為三個部分:OpenMP并行,opencv并行和多執行緒并行,在設計相關代碼時候,切記變數可以被多個執行緒訪問,但同一時間只能被一個執行緒修改,如果多個執行緒想修改同一個變數,可使用原子操作或加鎖, 當然,多核編程不止這些,還有tbb,mkl等等,

  • OpenMP 并行,這種并行辦法是最簡單的一種并行方法,直接在for回圈前面添加#pragma omp parallel for即可,程式會自動將for回圈分解,值得注意的是,該方法是在for回圈前開始創建執行緒,結束后并銷毀,這個程序會產生一些時間消耗,大約在3-5ms之間,做實時性應用開發的時候需要注意這個問題,下面給出了一個并行示例,當然openmp有多種操作函式,感興趣去找對應的開發教程即可,
#include <iostream>
#include <omp.h>

using namespace std;

int main() {
	omp_set_num_threads(4);
#pragma omp parallel for
	for (int i = 0; i < 3; i++)
		printf("i = %d, I am Thread %d\n", i, omp_get_thread_num());
	getchar();
}

// i = 0, I am Thread 0
// i = 1, I am Thread 1
// i = 2, I am Thread 2
  • OpenCV 并行, OpenCV提供了一種并行計算函式parallel_for_,內部集成多種并行框架,在c++11中,可以不必定一個類去繼承并行計算回圈體類ParallelLoopBody,可以直接使用,
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

class Parallel_My : public ParallelLoopBody
{
public:
    Parallel_My (Mat &img, const float x1, const float y1, const float scaleX, const float scaleY)
    : m_img(img), m_x1(x1), m_y1(y1), m_scaleX(scaleX), m_scaleY(scaleY){}

    virtual void operator ()(const Range& range) const
    {
        for (int r = range.start; r < range.end; r++) //process of for loop
        {
          /***
          這里寫每個執行緒要做的事情
          ***/
        }
    }
    Parallel_My& operator=(const Parallel_My &) {
        return *this;
    };
private:
    Mat &m_img;
    float m_x1, m_y1, m_scaleX, m_scaleY;
};

int main()
{
    Mat Img(480, 640, CV_8U1);
    float x1 = -2.1f, x2 = 0.6f, y1 = -1.2f, y2 = 1.2f;
    float scaleX = mandelbrotImg.cols / (x2 - x1), scaleY = mandelbrotImg.rows / (y2 - y1);

#ifdef CV_CXX11 // 使用lambda函式的示例
    parallel_for_(Range(0, Img.rows*tImg.cols), [&](const Range& range)
    {
        for (int r = range.start; r < range.end; r++) //這是需要并行計算的for回圈
        {
			// 自己補充函式
        }
    });
#else   // 默認情況下需要定義一個類,將引數全部傳進去,
    Parallel_My parallel_my0(Img, x1, y1, scaleX, scaleY);
    parallel_for_(Range(0, Img.rows*Img.cols), parallel_my0);
#endif
}
  • 多執行緒并行,上述的兩種方法是針對一個for回圈來解決的,但是整個演算法不可能就由一個for回圈構成,如果每個for回圈都這么做的話,創建執行緒的開銷巨大,因此,多執行緒并行主要就是解決這類問題的,初始化時候創建好執行緒,之后主執行緒串聯演算法,子執行緒解決for回圈問題,執行緒可能會使用同步,加鎖等手段逐步執行,最侄訓得輸出結果,創建多執行緒時候,系統本身就會將不同執行緒分到不同核心上,有自己的調度手段,所以該方法加速效果很明顯,就是過于面向程序,不方便后續的改進,

參考資料:
1 opencv 并行計算函式 parallel_for_的使用

3.3 CUDA 編程加速

CUDA加速其實是最好的加速手段,CUDA最大的特性就是核心數特別多,一般是幾千個,相比于CPU,加速倍數高達20-200倍之間,特別是推出的Jetson NX系列嵌入式卡,核心數在128-512之間,推進了更多演算法的落地應用,

如果想學習CUDA,我非常推薦下真本書,基礎的都涵蓋了,看完之后基本就能動手寫程式了,

CUDA開發主要還是有C語言風格,C++用的很少,切記一點避免在CUDA中動態分配記憶體,最好通過引數傳遞記憶體指標

下面給出一個向量加法示例,來簡單說明CUDA的用法,

#define N (33*1024)

// 核函式就是表示每個CUDA核心執行的函式,用關鍵字__global__ 表示
__global__ void add(int *a,int *b,int *c)
{
    int tid = threadIdx.x + blockIdx.x*blockDim.x;
    while(tid < N){
        c[tid] = a[tid] + b[tid];
        tid += blockDim.x*gridDim.x;
    }
}

int main(void)
{
    int a[N],b[N],c[N];
    int *dev_a,*dev_b,*dev_c;
    //在GPU上分配記憶體
    cudaMalloc((void**)&dev_a,N*sizeof(int));
    cudaMalloc((void**)&dev_b,N*sizeof(int));
    cudaMalloc((void**)&dev_c,N*sizeof(int));
    //在CPU上為陣列'a'和陣列'b'賦值
    for(int i=0;i<N;i++){
        a[i] = i;
        b[i] = i*i;
    }
    //將陣列‘a’和陣列‘b’復制到GPU記憶體中
    cudaMemcpy(dev_a,a,N*sizeof(int),cudaMemcpyHostToDevice);
    cudaMemcpy(dev_b,b,N*sizeof(int),cudaMemcpyHostToDevice);

    add<<<128,128>>>(dev_a,dev_b,dev_c);

    //將陣列‘C’從GPU復制到CPU中
    cudaMemcpy(c,dev_c,N*sizeof(int),cudaMemcpyDeviceToHost);
    //驗證GPU計算結果
    for(int i=0;i<N;i++){
        if(a[i]+b[i] != c[i]){
            printf("error:%d+%d=%d\n",a[i],b[i],c[i]);
        }
    }
    cudaFree(dev_a);
    cudaFree(dev_b);
    cudaFree(dev_c);
    return 0;
}

我曾經加速過經典導向濾波程式WGIF演算法,導向濾波核心是以每個像素為核心,根據周圍像素做濾波處理,在原始Matlab上的運算速度大約是20s左右,經過CUDA加速后,僅需要80ms即可跑完一張圖片,

在CPU上多執行緒開發遇到的一些同步、執行緒通信問題CUDA下都有,

對于一些常數記憶體,也就是不需要被修改的記憶體,CUDA給了很多種形式用于快速訪問:

  • 常量記憶體,限制為64kb
  • 紋理記憶體,多數應用于二維矩陣的訪問,

當然,更加詳細的用法,去看書即可,這里只是簡單介紹,

3.4 TensorRT 加速深度學習

TensorRT早期叫法叫GIE (GPU Inference Engine, GPU推理引擎),從名字上就知道這個東西用于推理(也就是測驗程序),Tensor可以理解為高維陣列,在TensorRT中,所有的資料都被組成最高四維的陣列,如果對應到CNN中其實就是 { N , C , H , W } \{N, C, H, W\} {N,C,H,W},N表示batch size,即多少張圖片或者多少個推斷(Inference)的實體;C表示channel數目;H和W表示影像或feature maps的高度和寬度,RT表示的是Runtime,

在深度學習的落地應用中,主要就是輸入圖片,推斷結果,模型如果做得不好,沒有做優化,可能需要500多ms才推斷完一張圖片,延遲較高,導致系統靈活性變弱,下圖紅色部分指的就是TensorRT要干的事,

在這里插入圖片描述
推斷的幾種特性:

  • 網路權值已經固定下來,無后向傳播程序,因此可以:
    • 模型固定,可以對計算圖進行優化
    • 輸入輸出大小固定,可以做memory優化
  • batch size要小一些,GPU利用率可能低些,
  • 可使用低精度技術推斷,深度學習網路引數一般為float32型別,這也是最小的浮點型別,很多研究表明可以用低精度,如半長(16)的float型別FP16,也可以用8位的整型(INT8)來做推斷,研究結果表明沒有特別大的精度損失,尤其對CNN,二值權值目前也在研究中,只不過FP16和INT8的研究使用相對來說比較成熟,低精度推斷的優點很明顯:速度快、記憶體低

在這里插入圖片描述
而TensorRT所做的優化,主要有以下幾點:

  • 合并了一些固定順序層,比如合并了卷積層、batchnorm層和激活層,取名為CBR層,
  • 取消無用層,比如concat層,實際上就是拼接特征,這里做了優化,
  • TensorRT在多種嵌入式設備都提供了驅動支持,

下面給出的一種網路,就非常適合用TensorRT優化,

在這里插入圖片描述
總的來說,盡管TensorRT做了很多優化,但加速效果普遍在20%左右,做好剪枝或改變資料型別可以提升2-3倍的性能,TensorRT只是在計算上優化了,想變得更快還是得想辦法設計出一個更加輕量的網路,

參考資料:
1 高性能深度學習支持引擎實戰——TensorRT

4 匯編加速

用匯編加速的方法往往指的是C/C++與匯編混合編程,盡管多種編譯器均有優化等級選項,但是越是高級的語言,時間損耗越多

什么時候使用匯編加速呢? 一般有兩種情況需要嵌入匯編代碼:

  • ① 升級專案,專案原始版本是匯編代碼,現在需要用C++開發,重寫匯編代碼注定耗時,直接呼叫匯編是個很好的解決方案,
  • ② 不同的語言對演算法一半都有特定的處理方法,比如Matlab之類盡量使用矩陣運算,C++盡量使用指標訪問等,如果有個頻繁呼叫的演算法,在匯編上有獨特的計算方法,那么直接在C++呼叫這個匯編函式,可以達到加速效果,

如何嵌入匯編代碼呢? 方法很簡單,使用關鍵字__asm來加入一段匯編語言的程式,C++下具體的格式為:__asm{ 指令 [;指令] /* comments */ ... 指令}

在C語言下,格式為:

asm [ volatile ] (
assembler template
[ : output operands ] /* optional /
[ : input operands ] / optional /
[ : list of clobbered registers ] / optional */
);

下面給一個示例(VS x64似乎不支持匯編擴展,我僅僅是見別人的演算法中用過,自己沒開發過),

#include <stdio.h>
/* 賦值 */
static int value_assignment(int input) {
  int ret = 0;
  asm volatile(
    /* ret = input */
    "movl %1, %0\n" /* 通過占位符指定互動的變數 : %0:ret %1:input*/
    :"=r"(ret) 
    :"r"(input)
  );
  return ret;
}

int main() {
  int input = 1;
  int ret = value_assignment(input);
  printf("input = %d\n", input);
  printf("ret = %d\n", ret);
  return 0;
}
// 列印結果:
// input = 1
// ret = 1

5 硬體加速

前面介紹了各種通過編程加速的方法,核心是將演算法進行并行化處理,總的來說

  • 多核并行,啟動并行時需要開多執行緒,需要少量的時間(<10ms),因此僅適用耗時較長的演算法(>100ms)的并行,
  • CUDA并行,演算法不可避免串行程序,因此許多時間在記憶體和顯存之間的拷貝,
  • CPU指定集,小規模加速,但僅限于各種基本運算操作(加減乘除、位運算等),

如今,FPGA是日趨熱門的一種加速方法,與軟體加速不同,該方法是直接將演算法設計在電路上,變成專有模塊進行并行,
在這里插入圖片描述
FPGA是目前新的一種低功耗加速設備,雖然通用的CPU主頻很高,但做某個特定運算(如影像處理中的Sobel)可能需要很多個時鐘周期;而FPGA可以通過編程重組電路,直接生成專用電路,加上電路并行性,可能做這個特定運算只需要一個時鐘周期,舉例來說,CPU主頻3GHz,FPGA主頻500MHz,若做某個特定運算CPU需要15個時鐘周期,FPGA只需一個,則耗時情況: CPU:15/3GHz =5ns; FPGA:1/500MHz =2ns,可以看到,FPGA做這個特定運算速度比CPU塊,能幫助加速,

以影像處理中常見的Sobel演算法來說,在FPGA上的實作可以參考A FPGA based implementation of Sobel edge detection,達到這個速度已經可以與opencv的sobel速度媲美了,

在這里插入圖片描述

在一些經典演算法中,比如橢圓檢測,也是可以利用FPGA的,比如論文《Effective ellipse detection method in limited-performance embedded system》,就是FPGA和DSP的一種結合,利用FPGA進行預處理,利用DSP處理串行操作,以實作實時處理,

在這里插入圖片描述

6 光學加速

目前來說,顯卡的性能受制于能耗和物理極限,每次更新換代,感覺并沒有那么高的性能提升,多卡緩解這類問題,但是功耗實在太大,

光衍射深度神經網路,提出了一種非常新奇的思想,Science發表了加州大學洛杉磯分校(UCLA)研究人員的最新研究:All-optical machine learning using diffractive deep neural networks,他們使用 3D 列印打造了一套 “全光學” 人工神經網路,可以分析大量資料并以光速識別目標,它使用來自物體的光散射來識別目標,研究團隊先用計算機進行模擬,然后用 3D 列印機打造出 8 平方厘米的聚合物層,每個晶圓表面都是不平整的,目的是為了衍射來自目標的光線,

以手寫數字識別為例,設計了一個五層的DNN,訓練之后測驗,實作了91.75%的分類精度,根據這些數值結果,我們將這個5層的DNN 設計3D列印出來,每一層的面積為8cm×8cm,然后在衍射網路的輸出平面定義10個檢測器區域,
在這里插入圖片描述
光學電路深度學習是一項重大突破,光的延遲非常低,所需的功耗也是極低,如果未來的加工工藝更加成熟,未來將是一個非常幫的突破,

參考資料:
1 Science重磅!用光速實作深度學習,跟GPU說再見

7 總結

我認為作為科研作業者,應該掌握一些基本的加速方法,比如多執行緒、CUDA之類,很多專業,跑一些演算法,用Matlab跑好幾分鐘甚至好幾個小時才能出結果,大大降低了科研效率,這些開發語言完全可以套上C++的外殼進行加速,

在工業機械領域,很看重實時性,如果自己設計出的演算法效果又好,又能落地,那多完美,

當然,大多數的加速方法破壞了面向物件這個性質,高度程序化,所以,一般是當自己的程式確定不改了,實驗做完了,再去考慮加速,讓你的效果更上一層樓,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/277013.html

標籤:其他

上一篇:【干貨】AB實驗助力用戶體驗升級(含直播回放)

下一篇:MySQL提升筆記(3)日志檔案詳解

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more