Docker-Compose基礎與實戰,看這一篇就夠了

what & why

Compose 項目是 Docker 官方的開源項目,負責實現對 Docker 容器集群的快速編排。使用前面介紹的Dockerfile我們很容易定義一個單獨的應用容器。然而在日常開發工作中,經常會碰到需要多個容器相互配合來完成某項任務的情況。例如要實現一個 Web 項目,除了 Web 服務容器本身,往往還需要再加上後端的數據庫服務容器;再比如在分佈式應用一般包含若干個服務,每個服務一般都會部署多個實例。如果每個服務都要手動啟停,那麼效率之低、維護量之大可想而知。這時候就需要一個工具能夠管理一組相關聯的的應用容器,這就是Docker Compose。
Compose有2個重要的概念

  • 項目(Project):由一組關聯的應用容器組成的一個完整業務單元,在 docker-compose.yml 文件中定義。
  • 服務(Service):一個應用的容器,實際上可以包括若干運行相同鏡像的容器實例。

docker compose 安裝與卸載

安裝

二進制包在線安裝

curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 

sudo chmod +x /usr/local/bin/docker-compose

這個方法現在基本行不通,下載太慢了,不推薦使用。

二進制包離線安裝

https://github.com/docker/compose/releases/download/1.25.0/docker-compose-Linux-x86_64下載對應的安裝包,比如我下載了Linux-x86_64的。

將下載好的安裝包剪切到/usr/local/bin/docker-compose目錄下
mv /app/download/docker-compose-Linux-x86_64 /usr/local/bin/docker-compose

添加執行權限
sudo chmod +x /usr/local/bin/docker-compose

pip安裝

  • 先安裝好pip工具
#安裝依賴 
yum -y install epel-release 
#安裝PIP 
yum -y install python-pip 
#升級PIP 
pip install --upgrade pip
  • 驗證pip 版本
[root@tymonitor bin]# pip --version
pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7)
  • 安裝docker compose
    pip install -U docker-compose==1.25.0

  • 驗證docker compose版本
[root@tymonitor bin]# docker-compose --version
docker-compose version 1.25.0, build b42d419

安裝補全插件

curl -L https://raw.githubusercontent.com/docker/compose/1.25.0/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose

卸載

二進制卸載

rm /usr/local/bin/docker-compose

pip卸載

pip uninstall docker-compose

docker compose 重要命令

命令選項

  • -f, –file FILE 指定使用的 Compose 模板文件,默認為 docker-compose.yml,可以多次指定。
  • -p, –project-name NAME 指定項目名稱,默認將使用所在目錄名稱作為項目名。
  • –x-networking 使用 Docker 的可拔插網絡後端特性
  • –x-network-driver DRIVER 指定網絡後端的驅動,默認為 bridge
  • –verbose 輸出更多調試信息。
  • -v, –version 打印版本並退出。

常用&重要命令

  • config
    驗證 Compose 文件格式是否正確,若正確則显示配置,若格式錯誤显示錯誤原因。
    如:docker-compose -f skywalking.yml config
    此命令不會執行真正的操作,而是显示 docker-compose 程序解析到的配置文件內容:

  • images
    列出 Compose 文件中包含的鏡像。如docker-compose -f skywalking.yml images

  • ps
    列出項目中目前的所有容器。如docker-compose -f skywalking.yml ps

  • build
    構建(重新構建)項目中的服務容器。如:docker-compose -f skywalking.yml build,一般搭配自定義鏡像,比如編寫的Dockfile,功能類似於docker build .

  • up
    該命令十分強大(重點掌握),它將嘗試自動完成包括構建鏡像,(重新)創建服務,啟動服務,並關聯服務相關容器的一系列操作。如docker-compose -f skywalking.yml up。默認情況,docker-compose up 啟動的容器都在前台,控制台將會同時打印所有容器的輸出信息,可以很方便進行調試。

    如果使用docker-compose up -d將會在後台啟動並運行所有的容器。一般推薦生產環境下使用該選項。
    默認情況,如果服務容器已經存在,docker-compose up 將會嘗試停止容器,然後重新創建(保持使用 volumes-from 掛載的卷),以保證新啟動的服務匹配 docker-compose.yml 文件的最新內容。如果用戶不希望容器被停止並重新創建,可以使用 docker-compose up --no-recreate。這樣將只會啟動處於停止狀態的容器,而忽略已經運行的服務。如果用戶只想重新部署某個服務,可以使用 docker-compose up --no-deps -d <SERVICE_NAME> 來重新創建服務並後台停止舊服務,啟動新服務,並不會影響到其所依賴的服務。此命令有如下選項:
    ①:-d 在後台運行服務容器。
    ②:--no-color 不使用顏色來區分不同的服務的控制台輸出。
    ③:--no-deps 不啟動服務所鏈接的容器。
    ④:--force-recreate 強制重新創建容器,不能與 –no-recreate 同時使用。
    ⑤:--no-recreate 如果容器已經存在了,則不重新創建,不能與 –force-recreate 同時使用。
    ⑥:--no-build 不自動構建缺失的服務鏡像。
    ⑦:-t, --timeout TIMEOUT 停止容器時候的超時(默認為 10 秒)。

  • down
    此命令停止用up命令所啟動的容器並移除網絡,如docker-compose -f skywalking.yml down

  • stop
    格式為 docker-compose stop [options] [SERVICE...]
    停止已經處於運行狀態的容器,但不刪除它。通過 docker-compose start 可以再次啟動這些容器,如果不指定service則默認停止所有的容器。如docker-compose -f skywalking.yml stop elasticsearch
    選項:
    -t, --timeout TIMEOUT 停止容器時候的超時(默認為 10 秒)。

  • start
    啟動已經存在的服務容器。用法跟上面的stop剛好相反,如docker-compose -f skywalking.yml start elasticsearch

  • restart
    重啟項目中的服務。用法跟上面的stop,start一樣

  • logs
    格式為docker-compose logs [options] [SERVICE...]
    查看服務容器的輸出。默認情況下,docker-compose 將對不同的服務輸出使用不同的顏色來區分。可以通過 –no-color 來關閉顏色。該命令在調試問題的時候十分有用。如docker-compose -f skywalking.yml logs 查看整體的日誌,docker-compose -f skywalking.yml logs elasticsearch 查看單獨容器的日誌

docker compose 模板文件

模板文件是使用 Compose 的核心,涉及到的指令關鍵字也比較多。本文主要列出幾個常見&重要的指令,其他指令大家可以自行百度。
默認的模板文件名稱為 docker-compose.yml,格式為 YAML 格式。

version: '3'
services:
  elasticsearch:
    image: elasticsearch:6.8.5
    container_name: elasticsearch
    restart: always
    volumes:
      - /app/skywalking/elasticsearch/data:/usr/share/elasticsearch/data:rw
      - /app/skywalking/elasticsearch/conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
      - /app/skywalking/elasticsearch/conf/jvm.options:/usr/share/elasticsearch/config/jvm.options
      - /app/skywalking/elasticsearch/logs:/usr/share/elasticsearch/logs:rw
    environment:
      - TZ=Asia/Shanghai
      - xpack.monitoring.enabled=false
      - xpack.watcher.enabled=false
    ports:
      - "9200:9200"
      - "9300:9300"

注意每個服務都必須通過 image 指令指定鏡像或 build 指令(需要 Dockerfile)等來自動構建生成鏡像。如果使用 build 指令,在 Dockerfile 中設置的選項(例如:CMD, EXPOSE, VOLUME, ENV 等) 將會自動被獲取,無需在 docker-compose.yml 中重複設置。

常用&重要命令

  • images
    指定為鏡像名稱或鏡像 ID。如果鏡像在本地不存在,Compose 將會嘗試拉取這個鏡像。
image: apache/skywalking-oap-server:6.5.0
image: apache/skywalking-ui:6.5.0
  • ports
    暴露端口信息。
    使用宿主端口:容器端口 (HOST:CONTAINER) 格式,或者僅僅指定容器的端口(宿主將會隨機選擇端口)都可以,端口字符串都使用引號包括起來的字符串格式。
ports: 
    - "3000" 
    - "8080:8080" 
    - "127.0.0.1:8001:8001"
  • volumes
    數據卷所掛載路徑設置。可以設置為宿主機路徑(HOST:CONTAINER)或者數據卷名稱(VOLUME:CONTAINER),並且可以設置訪問模式 (HOST:CONTAINER:ro)。
volumes:
      - /app/skywalking/elasticsearch/data:/usr/share/elasticsearch/data:rw
      - conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
version: "3"
services:
  my_src:
    image: mysql:8.0
    volumes:
      - mysql_data:/var/lib/mysql
volumes:
  mysql_data:
  • ulimits
    指定容器的 ulimits 限制值。
    例如,指定最大進程數為 65535,指定文件句柄數為 20000(軟限制,應用可以隨時修改,不能超過硬限制) 和 40000(系統硬限制,只能 root 用戶提高)。
ulimits:
   nproc: 65535
   nofile:
     soft: 20000
     hard: 40000
  • depends_on
    解決容器的依賴、啟動先後的問題。以下例子中會先啟動 redis mysql 再啟動 web
version: '3'
services:
  web:
    build: .
    depends_on:
      - db
      - redis     
  redis:
    image: redis    
  db:
    image: mysql
  • environment
    設置環境變量。你可以使用數組或字典兩種格式。
environment:
      SW_STORAGE: elasticsearch
      SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
      
environment:
      - SW_STORAGE= elasticsearch
      - SW_STORAGE_ES_CLUSTER_NODES=elasticsearch:9200
  • restart
    指定容器退出后的重啟策略為始終重啟。該命令對保持服務始終運行十分有效,在生產環境中推薦配置為 always 或者 unless-stopped
    restart: always

docker-compose 實戰

首先我需要推薦兩件事:

  • 配置docker加速鏡像
    創建或修改/etc/docker/daemon.json
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
    "registry-mirrors": [
        "https://hub-mirror.c.163.com",
        "https://mirror.ccs.tencentyun.com",
        "https://reg-mirror.qiniu.co"
    ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
  • 給你的ide工具裝上docker插件

本次實戰我們以docker-compose部署skywalking為例。編寫skywalking.yml,內容如下。

version: '3.3'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.8.5
    container_name: elasticsearch
    restart: always
    ports:
      - 9200:9200
      - 9300:9300
    environment:
      discovery.type: single-node
    ulimits:
      memlock:
        soft: -1
        hard: -1
  oap:
    image: skywalking/oap
    container_name: oap
    depends_on:
      - elasticsearch
    links:
      - elasticsearch
    restart: always
    ports:
      - 11800:11800
      - 12800:12800
    environment:
      SW_STORAGE: elasticsearch
      SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
  ui:
    image: skywalking/ui
    container_name: ui
    depends_on:
      - oap
    links:
      - oap
    restart: always
    ports:
      - 8080:8080
    environment:
      SW_OAP_ADDRESS: oap:12800

部署完成后將其上傳至服務器,執行docker-compose -f /app/skywalking.yml up -d即可。

個人公眾號:JAVA日知錄 ,

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR 掌控什麼技術要點? 帶您認識其相關發展及效能

※高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

收購3c瘋!各款手機、筆電、相機、平板,歡迎來詢價!

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

設計模式之美學習(九):業務開發常用的基於貧血模型的MVC架構違背OOP嗎?

我們都知道,很多業務系統都是基於 MVC 三層架構來開發的。實際上,更確切點講,這是一種基於貧血模型的 MVC 三層架構開發模式。

雖然這種開發模式已經成為標準的 Web 項目的開發模式,但它卻違反了面向對象編程風格,是一種徹徹底底的面向過程的編程風格,因此而被有些人稱為反模式(anti-pattern)。特別是領域驅動設計Domain Driven Design,簡稱 DDD)盛行之後,這種基於貧血模型的傳統的開發模式就更加被人詬病。而基於充血模型的 DDD 開發模式越來越被人提倡。

基於上面的描述,我們先搞清楚下面幾個問題:

  • 什麼是貧血模型?什麼是充血模型?
  • 為什麼說基於貧血模型的傳統開發模式違反 OOP?
  • 基於貧血模型的傳統開發模式既然違反 OOP,那又為什麼如此流行?
  • 什麼情況下我們應該考慮使用基於充血模型的 DDD 開發模式?

什麼是基於貧血模型的傳統開發模式?

對於大部分的後端開發工程師來說,MVC 三層架構都不會陌生。

MVC 三層架構中的 M 表示 ModelV 表示 ViewC 表示 Controller。它將整個項目分為三層:展示層、邏輯層、數據層。MVC 三層開發架構是一個比較籠統的分層方式,落實到具體的開發層面,很多項目也並不會 100% 遵從 MVC 固定的分層方式,而是會根據具體的項目需求,做適當的調整。

比如,現在很多 Web 或者 App 項目都是前後端分離的,後端負責暴露接口給前端調用。這種情況下,我們一般就將後端項目分為 Repository 層、Service 層、Controller 層。其中,Repository 層負責數據訪問,Service 層負責業務邏輯,Controller 層負責暴露接口。當然,這隻是其中一種分層和命名方式。不同的項目、不同的團隊,可能會對此有所調整。不過,萬變不離其宗,只要是依賴數據庫開發的 Web 項目,基本的分層思路都大差不差。

再來看一下,什麼是貧血模型?

目前幾乎所有的業務後端系統,都是基於貧血模型的。舉一個簡單的例子來解釋一下。

////////// Controller+VO(View Object) //////////
public class UserController {
  private UserService userService; //通過構造函數或者IOC框架注入
  
  public UserVo getUserById(Long userId) {
    UserBo userBo = userService.getUser(userId);
    UserVo userVo = [...convert userBo to userVo...];
    return userVo;
  }
}

public class UserVo {//省略其他屬性、get/set/construct方法
  private Long id;
  private String name;
  private String cellphone;
}

////////// Service+BO(Business Object) //////////
public class UserService {
  private UserRepository userRepository; //通過構造函數或者IOC框架注入
  
  public UserBo getUserById(Long userId) {
    UserEntity userEntity = userRepository.getUserById(userId);
    UserBo userBo = [...convert userEntity to userBo...];
    return userBo;
  }
}

public class UserBo {//省略其他屬性、get/set/construct方法
  private Long id;
  private String name;
  private String cellphone;
}

////////// Repository+Entity //////////
public class UserRepository {
  public UserEntity getUserById(Long userId) { //... }
}

public class UserEntity {//省略其他屬性、get/set/construct方法
  private Long id;
  private String name;
  private String cellphone;
}

平時開發 Web 後端項目的時候,基本上都是這麼組織代碼的。其中,UserEntityUserRepository 組成了數據訪問層,UserBoUserService 組成了業務邏輯層,UserVoUserController 在這裏屬於接口層。

從代碼中可以發現,UserBo 是一個純粹的數據結構,只包含數據,不包含任何業務邏輯。業務邏輯集中在 UserService 中。我們通過 UserService 來操作 UserBo。換句話說,Service 層的數據和業務邏輯,被分割為 BOService 兩個類中。像 UserBo 這樣,只包含數據,不包含業務邏輯的類,就叫作貧血模型Anemic Domain Model)。同理,UserEntityUserVo 都是基於貧血模型設計的。這種貧血模型將數據與操作分離,破壞了面向對象的封裝特性,是一種典型的面向過程的編程風格。

什麼是基於充血模型的 DDD 開發模式?

首先,我們先來看一下,什麼是充血模型?

在貧血模型中,數據和業務邏輯被分割到不同的類中。充血模型Rich Domain Model)正好相反,數據和對應的業務邏輯被封裝到同一個類中。因此,這種充血模型滿足面向對象的封裝特性,是典型的面向對象編程風格。

接下來,再來看一下,什麼是領域驅動設計?

領域驅動設計,即 DDD,主要是用來指導如何解耦業務系統,劃分業務模塊,定義業務領域模型及其交互。領域驅動設計這個概念並不新穎,早在 2004 年就被提出了,到現在已經有十幾年的歷史了。不過,它被大眾熟知,還是基於另一個概念的興起,那就是微服務。

除了監控、調用鏈追蹤、API 網關等服務治理系統的開發之外,微服務還有另外一個更加重要的工作,那就是針對公司的業務,合理地做微服務拆分。而領域驅動設計恰好就是用來指導劃分服務的。所以,微服務加速了領域驅動設計的盛行。

領域驅動設計有點兒類似敏捷開發、SOAPAAS 等概念,聽起來很高大上,但實際上只值“五分錢”。即便你沒有聽說過領域驅動設計,對這個概念一無所知,只要你是在開發業務系統,也或多或少都在使用它。做好領域驅動設計的關鍵是,看你對自己所做業務的熟悉程度,而並不是對領域驅動設計這個概念本身的掌握程度。即便你對領域驅動搞得再清楚,但是對業務不熟悉,也並不一定能做出合理的領域設計。所以,不要把領域驅動設計當銀彈,不要花太多的時間去過度地研究它。

實際上,基於充血模型的 DDD 開發模式實現的代碼,也是按照 MVC 三層架構分層的。Controller 層還是負責暴露接口,Repository 層還是負責數據存取,Service 層負責核心業務邏輯。它跟基於貧血模型的傳統開發模式的區別主要在 Service 層。

在基於貧血模型的傳統開發模式中,Service 層包含 Service 類和 BO 類兩部分,BO 是貧血模型,只包含數據,不包含具體的業務邏輯。業務邏輯集中在 Service 類中。在基於充血模型的 DDD 開發模式中,Service 層包含 Service 類和 Domain 類兩部分。Domain 就相當於貧血模型中的 BO。不過,DomainBO 的區別在於它是基於充血模型開發的,既包含數據,也包含業務邏輯。而 Service 類變得非常單薄。總結一下的話就是,基於貧血模型的傳統的開發模式,重 ServiceBO;基於充血模型的 DDD 開發模式,輕 ServiceDomain

為什麼基於貧血模型的傳統開發模式如此受歡迎?

基於貧血模型的傳統開發模式,將數據與業務邏輯分離,違反了 OOP 的封裝特性,實際上是一種面向過程的編程風格。但是,現在幾乎所有的 Web 項目,都是基於這種貧血模型的開發模式,甚至連 Java Spring 框架的官方 demo,都是按照這種開發模式來編寫的。

面向過程編程風格有種種弊端,比如,數據和操作分離之後,數據本身的操作就不受限制了。任何代碼都可以隨意修改數據。既然基於貧血模型的這種傳統開發模式是面向過程編程風格的,那它又為什麼會被廣大程序員所接受呢?

第一點原因是,大部分情況下,我們開發的系統業務可能都比較簡單,簡單到就是基於 SQLCRUD 操作,所以,我們根本不需要動腦子精心設計充血模型,貧血模型就足以應付這種簡單業務的開發工作。除此之外,因為業務比較簡單,即便我們使用充血模型,那模型本身包含的業務邏輯也並不會很多,設計出來的領域模型也會比較單薄,跟貧血模型差不多,沒有太大意義。

第二點原因是,充血模型的設計要比貧血模型更加有難度。因為充血模型是一種面向對象的編程風格。我們從一開始就要設計好針對數據要暴露哪些操作,定義哪些業務邏輯。而不是像貧血模型那樣,我們只需要定義數據,之後有什麼功能開發需求,我們就在 Service 層定義什麼操作,不需要事先做太多設計。

第三點原因是,思維已固化,轉型有成本。基於貧血模型的傳統開發模式經歷了這麼多年,已經深得人心、習以為常。你隨便問一個旁邊的大齡同事,基本上他過往參与的所有 Web 項目應該都是基於這個開發模式的,而且也沒有出過啥大問題。如果轉向用充血模型、領域驅動設計,那勢必有一定的學習成本、轉型成本。很多人在沒有遇到開發痛點的情況下,是不願意做這件事情的。

什麼項目應該考慮使用基於充血模型的 DDD 開發模式?

基於貧血模型的傳統的開發模式,比較適合業務比較簡單的系統開發。相對應的,基於充血模型的 DDD 開發模式,更適合業務複雜的系統開發。比如,包含各種利息計算模型、還款模型等複雜業務的金融系統。

這兩種開發模式,落實到代碼層面,區別不就是一個將業務邏輯放到 Service 類中,一個將業務邏輯放到 Domain 領域模型中嗎?為什麼基於貧血模型的傳統開發模式,就不能應對複雜業務系統的開發?而基於充血模型的 DDD 開發模式就可以呢?

實際上,除了我們能看到的代碼層面的區別之外(一個業務邏輯放到 Service 層,一個放到領域模型中),還有一個非常重要的區別,那就是兩種不同的開發模式會導致不同的開發流程。基於充血模型的 DDD 開發模式的開發流程,在應對複雜業務系統的開發的時候更加有優勢。為什麼這麼說呢?先來回憶一下,我們平時基於貧血模型的傳統的開發模式,都是怎麼實現一個功能需求的。

不誇張地講,我們平時的開發,大部分都是 SQL 驅動(SQL-Driven)的開發模式。我們接到一個後端接口的開發需求的時候,就去看接口需要的數據對應到數據庫中,需要哪張表或者哪幾張表,然後思考如何編寫 SQL 語句來獲取數據。之後就是定義 EntityBOVO,然後模板式地往對應的 RepositoryServiceController 類中添加代碼。

業務邏輯包裹在一個大的 SQL 語句中,而 Service 層可以做的事情很少。SQL 都是針對特定的業務功能編寫的,復用性差。當我要開發另一個業務功能的時候,只能重新寫個滿足新需求的 SQL 語句,這就可能導致各種長得差不多、區別很小的 SQL 語句滿天飛。

所以,在這個過程中,很少有人會應用領域模型、OOP 的概念,也很少有代碼復用意識。對於簡單業務系統來說,這種開發方式問題不大。但對於複雜業務系統的開發來說,這樣的開發方式會讓代碼越來越混亂,最終導致無法維護。

如果我們在項目中,應用基於充血模型的 DDD 的開發模式,那對應的開發流程就完全不一樣了。在這種開發模式下,我們需要事先理清楚所有的業務,定義領域模型所包含的屬性和方法。領域模型相當於可復用的業務中間層。新功能需求的開發,都基於之前定義好的這些領域模型來完成。

越複雜的系統,對代碼的復用性、易維護性要求就越高,我們就越應該花更多的時間和精力在前期設計上。而基於充血模型的 DDD 開發模式,正好需要我們前期做大量的業務調研、領域模型設計,所以它更加適合這種複雜系統的開發。

重點回顧

平時做 Web 項目的業務開發,大部分都是基於貧血模型的 MVC 三層架構,這裏把它稱為傳統的開發模式。之所以稱之為“傳統”,是相對於新興的基於充血模型的 DDD 開發模式來說的。基於貧血模型的傳統開發模式,是典型的面向過程的編程風格。相反,基於充血模型的 DDD 開發模式,是典型的面向對象的編程風格。

不過,DDD 也並非銀彈。對於業務不複雜的系統開發來說,基於貧血模型的傳統開發模式簡單夠用,基於充血模型的 DDD 開發模式有點大材小用,無法發揮作用。相反,對於業務複雜的系統開發來說,基於充血模型的 DDD 開發模式,因為前期需要在設計上投入更多時間和精力,來提高代碼的復用性和可維護性,所以相比基於貧血模型的開發模式,更加有優勢。

思考

  • 對於舉的例子中,UserEntityUserBoUserVo 包含的字段都差不多,是否可以合併為一個類呢?

參考:

本文由博客一文多發平台 發布!
更多內容請點擊我的博客

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR 掌控什麼技術要點? 帶您認識其相關發展及效能

※高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

收購3c瘋!各款手機、筆電、相機、平板,歡迎來詢價!

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

如何使用C#調用C++類虛函數(即動態內存調用)

  本文講解如何使用C#調用只有.h頭文件的c++類的虛函數(非實例函數,因為非虛函數不存在於虛函數表,無法通過類對象偏移計算地址,除非用export導出,而gcc默認是全部導出實例函數,這也是為什麼msvc需要.lib,如果你不清楚但希望了解,可以選擇找我擺龍門陣),並以COM組件的c#直接調用(不需要引用生成introp.dll)舉例。

  我們都知道,C#支持調用非託管函數,使用P/Inovke即可方便實現,例如下面的代碼

[DllImport("msvcrt", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl)]
public static extern void memcpy(IntPtr dest, IntPtr src, int count);

不過使用DllImport只能調用某個DLL中標記為導出的函數,我們可以使用一些工具查看函數導出,如下圖

一般會導出的函數,都是c語言格式的。

  C++類因為有多態,所以內存中維護了一個虛函數表,如果我們知道了某個C++類的內存地址,也有它的頭文件,那麼我們就能自己算出想要調用的某個函數的內存地址從而直接call,下面是一個簡單示例

#include <iostream>

class A_A_A {
public:
    virtual void hello() {
        std::cout << "hello from A\n";
    };
};

//typedef void (*HelloMethod)(void*);

int main()
{
    A_A_A* a = new A_A_A();
    a->hello();

    //HelloMethod helloMthd = *(HelloMethod *)*(void**)a;
    
    //helloMthd(a);
    (*(void(**)(void*))*(void**)a)(a);

    int c;
    std::cin >> c;
}

(上文中將第23行註釋掉,然後將其他註釋行打開也是一樣的效果,可能更便於閱讀)
從代碼中大家很容易看出,c++的類的內存結構是一個虛函數表二級指針(數組,多重繼承時可能有多個),每個虛函數表又是一個函數二級指針(數組,多少個虛函數就有多少個指針)。上文中我們假使只知道a是一個類對象,它的第一個虛函數是void (*) (void)類型的,那麼我們可以直接call它的函數。

  接下來開始騷操作,我們嘗試用c#來調用一個c++的虛函數,首先寫一個c++的dll,並且我們提供一個c格式的導出函數用於提供一個new出的對象(畢竟c++的new操作符很複雜,而且實際中我們經常是可以拿到這個new出來的對象,後面的com組件調用部分我會詳細說明),像下面這樣

dll.h

class DummyClass {
private:
    virtual void sayHello();
};

dll.cpp

#include "dll.h"
#include <stdio.h>

void DummyClass::sayHello() {
    printf("Hello World\n");
}

extern "C" __declspec(dllexport) DummyClass* __stdcall newObj() {
    return new DummyClass();
}

我們編譯出的dll長這樣

讓我們編寫使用C#來調用sayHello

using System;
using System.Runtime.InteropServices;

namespace ConsoleApp2
{
    class Program
    {
        [DllImport("Dll1", EntryPoint = "newObj")]
        static extern IntPtr CreateObject();

        [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
        delegate void voidMethod1(IntPtr thisPtr);

        static void Main(string[] args)
        {
            IntPtr dummyClass = CreateObject();
            IntPtr vfptr = Marshal.ReadIntPtr(dummyClass);
            IntPtr funcPtr = Marshal.ReadIntPtr(vfptr);
            voidMethod1 voidMethod = (voidMethod1)Marshal.GetDelegateForFunctionPointer(funcPtr, typeof(voidMethod1));
            voidMethod(dummyClass);

            Console.ReadKey();
        }
    }
}

(因為調用的是c++的函數,所以this指針是第一個參數,當然,不同調用約定時它入棧方式和順序不一樣)
下面有一種另外的寫法

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

namespace ConsoleApp2
{
    class Program
    {
        [DllImport("Dll1", EntryPoint = "newObj")]
        static extern IntPtr CreateObject();

        //[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
        //delegate void voidMethod1(IntPtr thisPtr);

        static void Main(string[] args)
        {
            IntPtr dummyClass = CreateObject();
            IntPtr vfptr = Marshal.ReadIntPtr(dummyClass);
            IntPtr funcPtr = Marshal.ReadIntPtr(vfptr);
            /*voidMethod1 voidMethod = (voidMethod1)Marshal.GetDelegateForFunctionPointer(funcPtr, typeof(voidMethod1));
            voidMethod(dummyClass);*/

            AssemblyName MyAssemblyName = new AssemblyName();
            MyAssemblyName.Name = "DummyAssembly";
            AssemblyBuilder MyAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName, AssemblyBuilderAccess.Run);
            ModuleBuilder MyModuleBuilder = MyAssemblyBuilder.DefineDynamicModule("DummyModule");
            MethodBuilder MyMethodBuilder = MyModuleBuilder.DefineGlobalMethod("DummyFunc", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { typeof(int) });
            ILGenerator IL = MyMethodBuilder.GetILGenerator();

            IL.Emit(OpCodes.Ldarg, 0);
            IL.Emit(OpCodes.Ldc_I4, funcPtr.ToInt32());

            IL.EmitCalli(OpCodes.Calli, CallingConvention.ThisCall, typeof(void), new Type[] { typeof(int) });
            IL.Emit(OpCodes.Ret);

            MyModuleBuilder.CreateGlobalFunctions();

            MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("DummyFunc");

            MyMethodInfo.Invoke(null, new object[] { dummyClass.ToInt32() });

            Console.ReadKey();
        }
    }
}

上文中的方法雖然複雜了一點,但……就是沒什麼用。不用懷疑!

文章寫到這裏,可能有童鞋就要發問了。你說這麼多,tmd到底有啥用?那接下來,我舉一個栗子,activex組件的直接調用!
以前,我們調用activex組件需要做很多複雜的事情,首先需要使用命令行調用regsvr32將dll註冊到系統,然後回到vs去引用com組件是吧

  仔細想想,需要嗎?並不需要,因為兩個原因:

  • COM組件規定DLL需要給出一個DllGetClassObject函數,它就可以為我們在DLL內部new一個所需對象
  • COM組件返回的對象其實就是一個只有虛函數的C++類對象(COM組件規定屬性和事件用getter/setter方式實現)
  • COM組件其實不需要用戶手動註冊,執行regsvr32會操作註冊表,而且32位/64位會混淆,其實regsvr32隻是調用了DLL導出函數DllRegisterServer,而這個函數的實現一般只是把自己註冊到註冊表中,這一步可有可無(特別是對於我們已經知道某個activex的dll存在路徑且它能提供的服務時,如果你非要註冊,使用p/invoke調用該dll的DllRegisterServer函數是一樣的效果)

因此,假如我們有一個activex控件(例如vlc),我們希望把它嵌入我們程序中,我們先看看常規的做法(本文沒有討論帶窗體的vlc,因為窗體這塊兒又複雜一些),直接貼圖:

看起來很簡單,但當我們需要打包給客戶使用時就很麻煩,涉及到嵌入vlc的安裝程序。而當我們會動態內存調用之後,就可以不註冊而使用vlc的功能,我先貼出代碼:

using System;
using System.Runtime.InteropServices;

namespace ConsoleApp3
{
    class Program
    {
        [DllImport("kernel32")]
        static extern IntPtr LoadLibraryEx(string path, IntPtr hFile, int dwFlags);
        [DllImport("kernel32")]
        static extern IntPtr GetProcAddress(IntPtr dll, string func);

        delegate int DllGetClassObject(Guid clsid, Guid iid, ref IntPtr ppv);

        delegate int CreateInstance(IntPtr _thisPtr, IntPtr unkown, Guid iid, ref IntPtr ppv);

        delegate int getVersionInfo(IntPtr _thisPtr, [MarshalAs(UnmanagedType.BStr)] out string bstr);

        static void Main(string[] args)
        {
            IntPtr dll = LoadLibraryEx(@"D:\Program Files\VideoLAN\VLC\axvlc.dll", default, 8);
            IntPtr func = GetProcAddress(dll, "DllGetClassObject");
            DllGetClassObject dllGetClassObject = (DllGetClassObject)Marshal.GetDelegateForFunctionPointer(func, typeof(DllGetClassObject));

            Guid vlc = new Guid("2d719729-5333-406c-bf12-8de787fd65e3");
            Guid clsid = new Guid("9be31822-fdad-461b-ad51-be1d1c159921");
            Guid iidClassFactory = new Guid("00000001-0000-0000-c000-000000000046");
            IntPtr objClassFactory = default;
            dllGetClassObject(clsid, iidClassFactory, ref objClassFactory);
            CreateInstance createInstance = (CreateInstance)Marshal.GetDelegateForFunctionPointer(Marshal.ReadIntPtr(Marshal.ReadIntPtr(objClassFactory) + IntPtr.Size * 3), typeof(CreateInstance));
            IntPtr obj = default;
            createInstance(objClassFactory, default, vlc, ref obj);
            getVersionInfo getVersion = (getVersionInfo)Marshal.GetDelegateForFunctionPointer(Marshal.ReadIntPtr(Marshal.ReadIntPtr(obj) + IntPtr.Size * 18), typeof(getVersionInfo));
            string versionInfo;
            getVersion(obj, out versionInfo);

            Console.ReadKey();
        }
    }
}

  上文中的代碼有幾處可能大家不容易懂,特別是指針偏移量的運算,這裏面有比較複雜的地方,文章篇幅有限,下來咱們細細研究。

  從11年下半年開始學習編程到現在已經很久了,有時候會覺得沒什麼奔頭。其實人生,無外乎兩件事,愛情和青春,我希望大家能有抓住的,就不要放手。兩年前,我為了要和一個女孩子多說幾句話,給人家講COM組件,其實我連c++有虛函數表都不知道,時至今日,我已經失去了她。今後怕是一直會任由靈魂遊盪,半夢半醒,即是人生。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

※公開收購3c價格,不怕被賤賣!

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

在React舊項目中安裝並使用TypeScript的實踐

前言

本篇文章默認您大概了解什麼是TypeScript,主要講解如何在React舊項目中安裝並使用TypeScript。

寫這個的目的主要是網上關於TypeScript這塊的講解雖然很多,但都是一些語法概念或者簡單例子,真正改造一個React舊項目使用TypeScript的文章很少。

所以在這裏記錄下改造一個React項目的實踐。

博客內容部分參照 ,這個網站有官方文檔的中文版。

安裝TypeScript及相關庫

對於集成了TypeScript的腳手架可以略過這一步,這裏主要講一下如何將TypeScript集成到一個React腳手架中。

首先執行

npm install --save @types/react @types/react-dom

這一步主要是為了獲取react和react-dom的聲明文件,因為並不是所有的庫都有TypeScript的聲明文件,所以通過運行

npm install --save @types/庫名字

的方式來獲取TypeScript的聲明文件。

只有獲取了聲明文件,才能實現對這個庫的類型檢查。

如果你使用了一些其它的沒有聲明文件的庫,那麼可能也需要這麼做。

然後運行命令:

npm install --save-dev typescript awesome-typescript-loader source-map-loader

這一步,我們安裝了typescript、awesome-typescript-loader和source-map-loader。

awesome-typescript-loader可以讓Webpack使用TypeScript的標準配置文件tsconfig.json編譯TypeScript代碼。

source-map-loader使用TypeScript輸出的sourcemap文件來告訴webpack何時生成自己的sourcemaps,源碼映射,方便調試。

添加TypeScript配置文件

在項目根目錄下創建一個tsconfig.json文件,以下為內容示例:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true, // 允許從沒有設置默認導出的模塊中默認導入。這並不影響代碼的輸出,僅為了類型檢查。
    "outDir": "./dist/", // 重定向輸出目錄
    "sourceMap": true, // 生成相應的 .map文件
    "noImplicitAny": true, // 在表達式和聲明上有隱含的 any類型時報錯。
    "module": "esnext", // 模塊引入方式
    "target": "esnext", // 指定ECMAScript目標版本
    "moduleResolution": "node", // 決定如何處理模塊
    "lib": [
      "esnext",
      "dom"
    ], // 編譯過程中需要引入的庫文件的列表。
    "skipLibCheck": true, //忽略所有庫中的聲明文件( *.d.ts)的類型檢查。
    "jsx": "react" // 在 .tsx文件里支持JSX
  },
  "include": [
    "./src/**/*", // 這個表示處理根目錄的src目錄下所有的.ts和.tsx文件,並不是所有文件
  ]
}

skipLibCheck非常重要,並不是每個庫都能通過typescript的檢測。

moduleResolution設為node也很重要。如果不這麼設置的話,找聲明文件的時候typescript不會在node_modules這個文件夾中去找。

更多配置文件信息可以參考:。

配置webpack

這裏列出一些TypeScript需要在webpack中使用的配置。

解析tsx文件的rule配置

示例如下:

module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['react', 'env', 'stage-0', 'stage-3'],
            plugins: [
              'transform-decorators-legacy',
              ['import', { libraryName: 'antd', style: 'css' }], // `style: true` 會加載 less 文件
            ],
          },
        },
      },
      { test: /\.tsx?$/, loader: "awesome-typescript-loader" }
      //...
    ]
    //...
}

其實就只是多加了一行:

{ test: /\.tsx?$/, loader: "awesome-typescript-loader" }

注意這一行需要加在解析jsx的rule下面,因為rule的執行順序是從下往上的,先解析tsx和ts再解析js和jsx。

當然用

enforce: 'pre'

調整過rule順序的可以不用在意這一點。

解決使用css-moudule的問題

如果代碼中使用了以下這種代碼:

import styles from './index.css'

那麼很可能報下面的錯:

Cannot find module './index.css'

解決方法就是在根目錄下新建文件一個叫declaration.d.ts的文件,內容為:

declare module '*.css' {
  const content: any;
  export default content;
}

這行代碼就是為所有的css文件進行聲明。

同時需要更改一下我們之前的tsconfig.json文件,將這個文件路徑放在include中:

"include": [
  "./src/**/*", 
  "./declaration.d.ts"
]

這個問題有通過安裝一些庫來解決的辦法,但是會給每個css生成一個聲明文件,感覺有點奇怪,我這裏自己考慮了一下採用了上面這種方法。

用於省略後綴名的配置

如果你慣於在使用

import Chart from './Chart/index.jsx'

時省略後綴,即:

import Chart from './Chart/index'

那麼在webpack的resolve中同樣需要加入ts和tsx:

resolve: {
  extensions: [".ts", ".tsx", ".js", ".jsx"]
},

引入Ant Design

實際上這個東西Ant Design的官網上就有怎麼在TypeScript中使用:。

那麼為什麼還是要列出來呢?

因為這裏要指出,對於已經安裝了Ant Design的舊項目而言(一般都是配了按需加載的吧),在安裝配置TypeScript時上面這個文檔基本沒有任何用處。

在網上可以搜到的貌似都是文檔中的方案,而實際上我們需要做的只是安裝ts-import-plugin

npm i ts-import-plugin --save-dev

然後結合之前的 awesome-typescript-loader ,在webpack中進行如下配置

const tsImportPluginFactory = require('ts-import-plugin')

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: "awesome-typescript-loader",
        options: {
          getCustomTransformers: () => ({
            before: [tsImportPluginFactory([
              {
                libraryName: 'antd',
                libraryDirectory: 'lib',
                style: 'css'
              }
            ])]
          }),
        },
        exclude: /node_modules/
      }
    ]
  },
  // ...
}

配置完成,修改前的準備

注意,直到這一步,實際上您的項目在編譯過程中仍然沒有用到TypeScript。

因為我們這裏只會用TypeScript處理.ts和.tsx後綴的文件,除非在配置中將allowJs設為true。

在使用之前,默認您已經對TypeScript語法有了了解,不了解可以參考:。

也就是說,經過了上面的這些步驟,您的原有代碼在不改動後綴的情況下應該是可以繼續用的。

如果要使用TypeScript,那麼新建tsx和ts文件,或者修改原有的文件後綴名即可。

接下來會列出一些典型的修改示例。

函數式組件的修改示例(含children)

import React from 'react'
import styles from './index.css'

interface ComputeItemProps {
  label: string;
  children: React.ReactNode;
}

function ComputeItem({ label, children }: ComputeItemProps) {
  return <div className={styles['item']}>
    <div className={styles['label']}>{label}:</div>
    <div className={styles['content']}>{children}</div>
  </div>
}
export default ComputeItem

這個例子中語法都可以在TypeScript的官網查到,唯一需要注意的是children的類型是React.ReactNode。

class組件修改示例(含函數聲明,事件參數的定義)

import React from 'react'
import styles from './index.css'

interface DataSourceItem {
  dayOfGrowth: string;
  netValueDate: string;
}

interface ComputeProps {
  fundCode: string;
  dataSource: DataSourceItem[];
  onChange(value: Object): void;
}

export default class Compute extends React.Component<ComputeProps, Object> {
  // 改變基金代碼
  handleChangeFundCode = (e: React.ChangeEvent<HTMLInputElement>) => {
    const fundCode = e.target.value
    this.props.onChange({
      fundCode
    })

  }  
  render() {
      //...
    );
  }
}

這個例子展示如何聲明class組件:

React.Component<ComputeProps, Object>

語法雖然看起來很怪,但是這就是TypeScript中的泛型,以前有過C#或者Java經驗的應該很好理解。

其中,第一個參數定義Props的類型,第二個參數定義State的類型。

而react的事件參數類型應該如下定義:

React.ChangeEvent<HTMLInputElement>

這裏同樣使用了泛型,上面表示Input的Change事件類型。

而組件的Prop上有函數類型的定義,這裏就不單獨列出來了。

這幾個例子算是比較典型的TypeScript與React結合的例子。

處理window上的變量

使用寫在window上的全局變量會提示window上不存在這個屬性。

為了處理這點,可以在declaration.d.ts這個文件中定義變量:

// 定義window變量
interface Window{
  r:string[]
}

其中r是變量名。

總結

本來還想再多寫幾個示例的,但是Dota2版本更新了,導致我不想繼續寫下去了,以後如果有時間再更新常用的示例吧。

本篇文章只專註於在React舊項目中安裝並集成TypeScript,盡可能做到不涉及TypeScript的具體語法與介紹,因為介紹這些東西就不是一篇博客能搞定的了。

文章如有疏漏還請指正,希望能幫助到在TypeScript面前遲疑的你。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR 掌控什麼技術要點? 帶您認識其相關發展及效能

※高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

收購3c瘋!各款手機、筆電、相機、平板,歡迎來詢價!

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

物聯網架構成長之路(47)-利用GitLab實現CI持續集成

0.前言
  前段時間,考慮到要練習部署一套CI/CD的系統。一開始考慮到Jenkins,隨着這两天的了解,發現最新版的GitLab已經提供有CI/CD集成了。所以本次博客,乾脆一步到位,直接用GitLab裏面的CI/CD模塊。Jenkins可能需要更高級的應用場合。經過測試GitLab自帶的功能完全符合我的需求。

1. 安裝GitLab和GitLab-CI(gitlab-runner)
  英語比較好的,可以直接看官方文檔。https://docs.gitlab.com/omnibus/docker/#install-gitlab-using-docker-compose https://docs.gitlab.com/ee/ci/quick_start/README.html
  下面提供我使用的 docker-compose.yml

 1 version: '3'
 2 services:
 3     gitlab:
 4         image: twang2218/gitlab-ce-zh:latest
 5         #image: gitlab/gitlab-ce:rc
 6         restart: always
 7         hostname: '172.16.23.203'
 8         environment:
 9             GITLAB_OMNIBUS_CONFIG: |
10                 external_url 'http://172.16.23.203:8929'
11                 gitlab_rails["time_zone"] = "Asia/Shanghai"
12         ports:
13             - 8929:8929
14             - 1080:80
15             - 1443:443
16             - 1022:22
17         volumes:
18             - /root/workspace/docker/gitlab/1/config:/etc/gitlab
19             - /root/workspace/docker/gitlab/1/logs:/var/log/gitlab
20             - /root/workspace/docker/gitlab/1/data:/var/opt/gitlab
21     gitlab-runner:
22         image: gitlab/gitlab-runner:latest
23         restart: always
24         volumes:
25             - /root/workspace/docker/gitlab/2/config:/etc/gitlab-runner
26             - /var/run/docker.sock:/var/run/docker.sock

  執行docker-compose up -d 就運行起來,幾點需要說明的
    1. gitlab的image,可以選擇中文版或者英文版
    2. hostname 這裏指定本機IP地址
    3. gitlab環境變量,external_url表示提供訪問的IP和端口,時區配置上海
    4. 端口映射,默認是80端口,由於我上面配置了8929,所以映射8929到Host主機
    5. volumes 配置持久化數據
    6. 這裏的/var/run/docker.sock 要映射到主機,因為會用到主機的一些資源,同時還會在docker裏面安裝docker
  下面是運行效果,第一次運行會比較久,因為要拉取鏡像和初始化GitLab

2. 登錄使用GitLab
  首次登錄,設置密碼。 登錄默認用戶名是root
  利用模版,新建一個Spring項目

  利用IDE,或者其他工具,或者直接在GitLab修改代碼

3. 配置CI/CD,把機器(gitlab-runner)註冊到GitLab中
  可以在項目配置CI/CD機器,也可以在個人所有項目下配置,也可以由管理員配置所有項目下CI/CD機器。原理和流程都是一樣的,只是比Jenkins更加細粒度控制而已。

  進入gitlab-runner的Docker,執行初始化命令 gitlab-ci-multi-runner register,完整命令如下:

1 sudo docker exec -it gitlab-runner gitlab-ci-multi-runner register

  需要錄入的信息,安裝上圖進行,填寫,後續還可以修改。

  如果需要修改,可以修改之前volumes配置的路徑下, config/config.toml

 

 1 concurrent = 1
 2 check_interval = 0
 3 
 4 [session_server]
 5   session_timeout = 1800
 6 
 7 [[runners]]
 8   name = "myRunner"
 9   url = "http://172.16.23.203:8929/"
10   token = "96beefdaa54832b0c8369ffa3811c9"
11   executor = "docker"
12   [runners.custom_build_dir]
13   [runners.docker]
14     tls_verify = false
15     image = "docker:latest"
16     privileged = true
17     disable_entrypoint_overwrite = false
18     oom_kill_disable = false
19     disable_cache = false
20     volumes = ["/cache", "/root/.m2:/root/.m2", "/var/run/docker.sock:/var/run/docker.sock"]
21     shm_size = 0
22   [runners.cache]
23     [runners.cache.s3]
24     [runners.cache.gcs]

 

  上面這個是配置文件,裏面有幾個注意點
    1. privileged 這裏要配置 true,因為要在docker裏面安裝docker
    2. /root/.m2 這個是配置maven的倉庫使用宿主主機的緩存,這樣就不用每次CI都要下載依賴
    3. /var/run/docker.sock 這個也要配置,在構建dockerfile的時候會用到
  還有一個需要配置的就是,這個Runner需要設置tag,這個是標識Runner的名稱。在.gitlab-ci.yml中會用到

4. 配置CI/CD
  默認GitLab是啟用該功能的,根目錄配置新增 .gitlab-ci.yml 文件,然後每次git push,都會觸發CI持續集成。當然可以在yml配置,在主線master觸發。
  來個簡單的配置,測試一下

 1 image: maven:3-jdk-8
 2 cache:
 3     paths:
 4         - .m2/repository
 5 test:
 6     stage: test
 7     script:
 8         - mvn package
 9     tags:
10         - tag

  上面這個配置,寫到.gitlab-ci.yml然後提交到repo,我們提交該文件到gitlab對應項目上去。

1 git add .gitlab-ci.yml
2 git commit -m "Add .gitlab-ci.yml"
3 git push origin master

  如果嫌慢,pom.xml 可以換個阿里源

 1         <repository>
 2             <id>maven-ali</id>
 3             <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
 4             <releases>
 5                 <enabled>true</enabled>
 6             </releases>
 7             <snapshots>
 8                 <enabled>true</enabled>
 9                 <updatePolicy>always</updatePolicy>
10                 <checksumPolicy>fail</checksumPolicy>
11             </snapshots>
12         </repository>

  一提交,就會觸發自動構建

  可以看到整個構建過程,如果出現錯誤,也是到這個日誌裏面排查問題。

 

 

5. 測試、打包、發布
  這一步,我們實現一個簡單的測試、打包、發布
5.1 增加 Dockerfile

1 FROM openjdk:8-jdk-alpine
2 VOLUME /tmp
3 COPY  target/demo-0.0.1-SNAPSHOT.jar app.jar
4 ENV PORT 5000
5 EXPOSE $PORT
6 ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/app.jar"]

5.2 修改 .gitlab-ci.yml

 1 image: maven:3-jdk-8
 2 
 3 variables:
 4     DOCKER_TAG: test/demo-spring:0.1
 5 
 6 cache:
 7     paths:
 8         - .m2/repository
 9 
10 stages:
11     - test
12     - package
13     - deploy
14 
15 test:
16     stage: test
17     tags:
18         - tag
19     script:
20         - mvn test
21 
22 package:
23     stage: package
24     tags:
25         - tag
26     script:
27         - mvn clean package -Dmaven.test.skip=true
28     artifacts:
29         paths:
30             - target/*.jar
31 
32 deploy:
33     image: docker:latest
34     stage: deploy
35     services:
36         - docker:dind
37     tags:
38         - tag
39     script:
40         - docker version 
41         - docker build -t $DOCKER_TAG .
42         - docker rm -f test || true
43         - docker run -d --name test -p 5000:5000 $DOCKER_TAG

  那個artifacts.paths 配置,提交target目錄下的文件到下一個流水線,因為不同流水線,由於是基於Docker,所以每一步都是隔離的。同時,上傳的附件還可以在構建成功后,在流水線pipelines界面進行下載。每一步的image都是可以指定的,那個tags也是可以指定的。可以提交到不同的機器進行構建。
  上面一共就三步流程,先test(測試),然後package(打包編譯),最後deploy(發布測試)。前兩個比較好理解,就是maven的基本命令。最後那個deploy就是利用docker裏面的docker來進行打包成docker,然後運行起來,作為測試發布。
  更新代碼.gitlab-ci.yml,然後提交,觸發持續集成。

  查看構建日誌

  查看宿主機鏡像和運行狀態

  查看瀏覽器,已經發布到測試環境了

5.3 釘釘通知

 1 image: maven:3-jdk-8
 2 
 3 variables:
 4     DOCKER_TAG: test/demo-spring:0.1
 5 
 6 cache:
 7     paths:
 8         - .m2/repository
 9 
10 stages:
11     - test
12     - package
13     - deploy
14     - notify
15 
16 test:
17     stage: test
18     tags:
19         - tag
20     script:
21         - mvn test
22 
23 package:
24     stage: package
25     tags:
26         - tag
27     script:
28         - mvn clean package -Dmaven.test.skip=true
29     artifacts:
30         paths:
31             - target/*.jar
32 
33 deploy:
34     image: docker:latest
35     stage: deploy
36     services:
37         - docker:dind
38     tags:
39         - tag
40     script:
41         - docker version 
42         - docker build -t $DOCKER_TAG .
43         - docker rm -f test || true
44         - docker run -d --name test -p 5000:5000 $DOCKER_TAG
45 
46 notify:
47     image: appropriate/curl:latest
48     stage: notify
49     tags:
50         - tag
51     script: "curl 'https://oapi.dingtalk.com/robot/send?access_token=d6c15304c1***************************************' -H 'Content-Type: application/json' -d '{\"msgtype\": \"text\", \"text\": {\"content\": \"功能已更新部署至測試環境\"}}' "

  有了這個通知,就可以做很多事情了,寫個腳本,封裝成一個Docker 鏡像,可以發送釘釘,發送郵件,可以對接到第三方系統等。

  更多高級應用,如集成之前了解的Harbor,Rancher。使整個系統更加強大,更加智能化。

 

參考資料
  
  
  
  
  

本文地址:
本系列目錄:
個人主頁:

volumes

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR 掌控什麼技術要點? 帶您認識其相關發展及效能

※高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

收購3c瘋!各款手機、筆電、相機、平板,歡迎來詢價!

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台積電與格芯達成訴訟和解 現在及未來十年專利交互授權

  作者:蘇亞

  【TechWeb】10 月 29 日,台積電宣布與格芯(GlobalFoundries)達成專利訴訟和解,雙方同意撤回所有法律訴訟,並同意對現有及未來十年的半導體技術專利,達成全球專利交互授權協議。

  根據台積電公告,他們將駁回它們之間以及涉及其任何客戶的所有訴訟,兩家公司已經同意相互之間廣泛的專利壽命交叉許可,這些交叉許可適用於彼此在全球範圍內現有的半導體專利以及在未來十年內將要申請的專利,該決議保證了台積電和 GF 的運營自由,並確保各自的客戶將繼續獲得每個代工廠的完整技術和服務。

  “我們很高興很快達成這一承認我們各自知識產權實力的解決方案。今天的公告使我們兩家公司都能專註於創新並更好地為全球客戶提供服務。” GF 首席執行官 Thomas Caulfield 說。“ GF 與台積電之間的這項協議確保了 GF 的增長能力,並且是當今全球經濟核心的整個半導體行業的勝利。”

  半導體行業一直競爭激烈,驅使參与者追求創新,豐富了世界各地數百萬人的生活。台積電已投入數百億美元用於創新,以達到今天的領先地位。”台積電總顧問 Sylvia Fang 說。“這項決議是一項积極的進展,將使我們始終專註於滿足客戶對將不斷帶來創新的技術的需求,這將使整個半導體行業蓬勃發展和繁榮。”

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

平板收購,iphone手機收購,二手筆電回收,二手iphone收購-全台皆可收購

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

3c收購,鏡頭 收購有可能以全新價回收嗎?

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

雲孤島“混而不合” 戴爾推出一致性混合雲平台

  過去的幾十年,IT 基礎架構經歷了從大型機到 PC 機,從數據中心到移動互聯網、IoT 的變化,看起來我們總是在重複集中、分佈的循環演進過程,但戴爾公司認為,每一次的改變都不是簡單的重複,而是在原有基礎上的提升和發展。

  雲計算時代,企業 IT 戰略重點在不斷地轉移,企業看待雲計算的角度也不再以資源視角,而是更多從應用或者工作負載視角。

  在構建企業的核心數據架構以及釋放數據潛能的過程當中,IT 和 OT 的戰略重點在快速融合,創新理念到業務落地,數據管理到業務安全,全球展望到全球服務,所有這一切都在不斷推動每一家企業去實施新 IT 戰略——從資源平台的打造到創新平台的演進。

  為何需要戴爾科技雲平台?

  戴爾科技集團企業技術戰略架構師總監許良謀表示,隨着雲計算行業發展,一个中大型企業內部存在3-5 朵雲是非常正常的,假如企業客戶把關鍵應用放到公有雲,一定會考慮同時放在兩朵公有雲,再加上生產線私有雲,支持創新業務的測試雲、開發雲等,企業內部有3-5 朵相同或者不同的雲是正常現象。

  以戴爾集團本身為例,戴爾內部有超過 1200 個應用,涵蓋從售前、售後、供應鏈等各個環節,一朵雲解決想要所有的問題是不可能的,所以企業尋求多雲戰略是實際需求推動。

  但多雲同樣帶來困擾,戴爾科技集團全球資深副總裁、大中華區企業解決方案總經理曹志平解釋道,每家企業的應用和業務流程在不同的時間階段,需要不同的部署方式;每一個雲平台的技術特點不同,決定了它對某些工作負載支持效果好一點,對某些工作支持差一點;此外,多雲形態下的雲計算資源計費,很多用戶發現產生了跟預期偏差較大的情況,尤其是對於網絡資源消耗帶來的費用增長,企業用戶對這方面的估計不足。

  企業難以應付部署在各種雲平台上的工作負載,數據孤島變成了新的雲孤島,數據割裂導致企業在做整體業務規劃、整體戰略實施時徒增困難。

  雷鋒網了解到,今年年初,戴爾科技集團決定整合集團內部所有與雲計算相關的技術和資源,打造一套能夠充分利用各種雲平台技術的落地方案,尤其是 VMware 和戴爾易安信,兩者解決方案深度融合,推出了一個一致性的雲策略——戴爾科技雲平台。

  多雲至簡

  “戴爾科技集團的雲是一朵徹底的混合雲,基於 VMware Cloud Foundation 軟件定義數據中心,開發者無需注意應用所在位置。可以在最合適的位置來運行工作負載”,在一年一度的戴爾科技峰會主論壇演講中,戴爾公司創始人邁克爾·戴爾也着力推廣一致性混合雲。

  多雲至簡是戴爾混合雲解決方案的關鍵詞,看起來“多”和“簡”好像是兩個錯位的反義詞,多雲是企業擁抱雲架構演進的必然過程,至簡表示企業希望混合雲架構帶來價值,卻並不希望帶來額外的複雜。

  從技術視角看,戴爾混合雲解決方案是兩種能力的融合,其一是虛擬化技術,使企業 IT 能夠大規模整合資源,並將資源池化;其二是軟件定義數據中心技術,是把整個數據中心軟件化和敏捷化的關鍵技術。

  “對於一個企業來說,整個平台從資源平台轉型到創新平台,真正的用戶是創新者,創新者根本不用在乎底層平台是什麼技術實現,只要有創新的想法就可以迅速獲取創新所需要的平台”,VMware 大中華區技術部高級總監李剛說道。

  從戴爾混合雲解決方案視角看,不管是基於戴爾科技雲平台結合 VCF 和 VxRail 的方案,還是服務器+存儲三層架構的方案打造 VCF 的平台,戴爾的工作在於推動 VCF 與所有公有雲平台廠商做聯合,即在其他雲廠商的公有雲內部開闢 VMware 雲,這樣不論是數據、技術還是管理都能保持一致性。

  對於已經使用戴爾 EMC 或者 VMware 的企業用戶,保持技術的延續性,使用戴爾混合雲方案是自然的過程,而對其他非戴爾客戶,出於多雲的需求,嘗鮮使用戴爾混合雲方案就有可能轉化為戴爾企業級解決方案的用戶。

  而對戴爾,VMware 雲融於公有雲工作量倍增,戴爾要和不同公有雲平台兼容適配,還涉及到不同私有雲平台,客戶端至簡的代價必然是背後的供應商額外工作量,以戴爾的體量做一致性混合雲平台,也是建立技術和商業壁壘的策略。

  戴爾混合雲的差異化

  同推混合雲概念,戴爾的混合雲和其他雲廠商所強調的混合雲是否有不同?

  雷鋒網了解到,市場出現的所謂混合雲主要分為兩個方向:一種是公有雲廠商做私有雲方案,一家廠商的公私方案整合為混合雲方案;另一種是私有雲廠商開發的產品融合部分公有雲廠商產品,加以整合併推出的混合雲。

  許良謀用中西餐做形象比喻,一些混合雲方案只提供一個菜系,比如山東菜,一些混合雲方案中西餐混着吃,這些混合雲方案都相對封閉,戴爾則希望打造一個“唐人街”——不管是在國內還是國外,家裡還是外出,直接在“唐人街”就可以吃到喜歡的中餐。

  戴爾混合雲是業界支持公有雲平台數量最多的產品,VMware 目前也是全球私有雲環境市場佔有率最高的私有雲方案,這意味着企業客戶可以直接利用戴爾混合雲方案做利舊,保護歷史投資。

  技術支持能力和平台支持數量,以及整體市場佔有率,再加上技術優化細節,成為戴爾的差異化優勢。

  “真正讓用戶能夠擺脫雲孤島,所有的數據、所有的應用和工作負載,無論它的形式上是某個私有雲或者某個公有雲上,實質是在同一個管理平台,這就是戴爾科技集團雲平台的優勢、價值和意義”,戴爾科技集團全球資深副總裁、大中華區企業解決方案總經理曹志平總結道。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

平板收購,iphone手機收購,二手筆電回收,二手iphone收購-全台皆可收購

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

3c收購,鏡頭 收購有可能以全新價回收嗎?

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

格力“招親”落定人選 高瓴勝出

  作者:木子松

  【TechWeb】10 月 28 日晚間消息,格力電器公告,格力集團函告公司,經評審委員會對參与本次公開徵集的兩家意向受讓方進行綜合評審,確定珠海明駿投資合夥企業(有限合夥)為最終受讓方。

  公告內容显示,珠海明駿投資成立於 2017 年 5 月,背後實際操盤者是高瓴資本,旗下不同的產品分別出資組成的註冊於橫琴新區的新基金。

  以下是公告全文:

  關於控股股東擬協議轉讓公司部分股份公開徵集受讓方的結果公告

  本公司及董事會全體成員保證信息披露的內容真實、準確、完整,沒有虛假記載、誤導性陳述或重大遺漏。

  珠海格力電器股份有限公司(以下簡稱“格力電器”或“公司”)分別於 2019 年 4 月 1 日、2019 年 4 月 9 日、2019 年 8 月 13 日、2019 年 9 月 3 日披露了《重大事項停牌公告》(公告編號:2019-015)、《關於控股股東擬通過公開徵集受讓方的方式協議轉讓公司部分股權暨復牌的提示性公告》(公告編號: 2019-016)、《關於控股股東擬協議轉讓公司部分股份公開徵集受讓方的公告》(公告編號:2019-052)(以下簡稱“《公開徵集受讓方公告》”)、《關於控股股東擬協議轉讓公司部分股份公開徵集受讓方的進展公告》(公告編號: 2019-057)。

  2019 年 10 月 28 日,格力集團函告公司,經評審委員會對參与本次公開徵集的兩家意向受讓方進行綜合評審,確定珠海明駿投資合夥企業(有限合夥)(以下簡稱“珠海明駿”)為最終受讓方。

  一、最終受讓方的基本情況 

  二、最終受讓方維護管理層穩定的措施及合作方案

  根據《公開徵集受讓方公告》披露的公開徵集方案,意向受讓方應有利於提升上市公司質量,維護公司持續健康發展,且本次受讓申請材料中的受讓意向書要求意向受讓方提出維護管理層穩定的具體措施及未來與管理層合作的具體方案。

  基於上述要求,參与本次公開徵集的兩家意向受讓方珠海明駿投資合夥企業(有限合夥),以及格物厚德股權投資(珠海)合夥企業(有限合夥)與 GENESIS FINANCIAL INVESTMENT COMPANY LIMITED 組成的聯合體均在向格力集團提交的受讓申請材料中提出了維護管理層穩定的具體措施及合作方案。

  鑒於本次公開徵集的最終受讓方確定為珠海明駿,且珠海明駿已通過受讓意向書書面邀請的形式向格力電器管理層提出合作邀請,若格力電器管理層最終接受珠海明駿的邀請,並依據受讓意向書提出的邀請方案展開合作,雙方需在珠海明駿與格力集團簽署本次公開徵集的《股份轉讓協議》前對具體合作方案予以明確並對外披露。 前述合作方案為最終受讓方的單方面邀請,格力電器管理層是否接受最終受讓方的邀請以及雙方最終能否就合作方案達成一致尚存在不確定性,敬請廣大投資者注意投資風險。

  三、公開徵集後續安排

  根據《公開徵集受讓方公告》披露的公開徵集方案,意向受讓方應自被確定為最終受讓方之日(即本公告發布之日)起 10 個工作日內與格力集團簽訂《股份轉讓協議》,所簽署的《股份轉讓協議》仍須經國有資產監督管理機構及其他有權政府部門批准後方能生效,是否能夠獲得國有資產監督管理機構及其他有權政府部門的批准以及股份轉讓是否能夠最終完成尚存在不確定性,敬請廣大投資者注意投資風險。

  公司將與格力集團、格力電器管理層保持密切聯繫並根據相關事項進展情況,嚴格按照相關法律、法規的規定及時履行信息披露義務。公司指定的信息披露媒體為《證券日報》、《證券時報》、《上海證券報》、《中國證券報》和巨潮資訊網(www.cninfo.com.cn),敬請廣大投資者謹慎決策,注意投資風險。

  特此公告。

  珠海格力電器股份有限公司

  董事會

  二〇一九年十月二十九日

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

平板收購,iphone手機收購,二手筆電回收,二手iphone收購-全台皆可收購

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

3c收購,鏡頭 收購有可能以全新價回收嗎?

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

NASA發布太陽“怪異”照 看似最佳的萬聖節南瓜燈

  據外媒 BGR 報道,隨着萬聖節即將到來,美國宇航局(NASA)在其 Facebook 頁面上分享了一張特別怪異的太陽圖像,看起來像人們熟悉的萬聖節南瓜燈。該圖像是由目前正在繞地球運行的 NASA 太陽動力學天文台(Solar Dynamics Observatory)捕獲的。

  該天文台能夠捕捉到我們最近的恆星的一些令人難以置信的照片,但是這張特殊的圖像在距萬聖節只有幾天時間時發布具有特殊的意義。

  通過其強大的傳感器套件,該天文台可以以我們眼睛無法看到的方式觀察太陽。該圖像使用紫外線來揭示恆星表面上的活動區域,在這種情況下,它看起來就像是一張“咧嘴大笑的臉”。

  NASA 解釋道:

該圖像中的活動區域顯得更亮,因為這些區域會發出更多的光和能量。它們是在太陽大氣層電暈中盤旋的強烈而複雜的磁場的標誌。該圖像將兩組分別位於 171 和 193Ångströms 的極端紫外線波長混合在一起,通常以金色和黃色着色,以產生特別類似於萬聖節的外觀。

  這張照片最初是在 2014 年分享的,但它是 NASA 的最愛之一,並且自那以後的幾年裡,它多次出現。同時,太陽動力學天文台仍在努力工作,將太陽的新影像傳回地球,科學家將繼續研究和監測恆星。

  該航天器於 2010 年 2 月發射,任務期限長達十年。其已在太空中已經捕獲了超過 3.5 億張圖像,並將在可預見的未來繼續這樣做。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

平板收購,iphone手機收購,二手筆電回收,二手iphone收購-全台皆可收購

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

3c收購,鏡頭 收購有可能以全新價回收嗎?

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?

地平線發布旭日二代邊緣AI芯片,將算法演進趨勢融入BPU架構

  【新智元導讀】剛剛,地平線發布了最新的旭日二代邊緣 AI 芯片及全場景芯片解決方案。芯片集成地平線第二代 BPU 架構,同時將算法演進趨勢融入 BPU 架構。

  8 月 30 日,地平線投下一顆“重磅炸彈”:正式宣布量產中國首款車規級 AI 芯片——征程二代,成為攀登自動駕駛制高點的里程碑事件。

  兩個月不到,地平線再次宣布 AI 芯片新進展,於今日宣布推出新一代 AIoT 智能應用加速引擎——旭日二代邊緣 AI 芯片全場景芯片解決方案

  集成地平線第二代 BPU 架構,每秒處理超過 700 張圖片

  今天,地平線聯合創始人&技術副總裁黃暢發布並詳細解讀了旭日二代芯片:

  旭日二代是地平線面向未來物聯網推出的新一代智能應用加速引擎,也是地平線在自動駕駛芯片領域技術先發優勢的一次成功遷移

  旭日二代集成地平線第二代 BPU 架構(伯努利架構),典型算法模型算力利用率>90%;配合高效算法,每 TOPS 算力可處理的幀數高於標稱 4T 算力的 AI 芯片(>10 倍,同等算力 GPU)。

  針對物聯網場景下的主要目標群體“人”和“車”,旭日二代進行了大量的算法優化,在邊緣端即可實現全視頻結構化能力,高效靈活地處理多類 AI 任務,包括 10~30 萬人前端識別,密集人群時空屬性行為分析,多種非機動車、機動車檢測分類。

  旭日二代具備四大核心優勢

  • 高性能:等效算力 4Tops,可實時處理多類 AI 任務 
  • 低功耗:採用 28 HPC+ 低功耗 CMOS 工藝, 典型功耗 2 W
  • 開放工具鏈:可視化調試工具、豐富的算法樣例
  • 視頻全結構化能力:支持對多類人、車目標進行實時檢測和精準識別

  實際測試表明,旭日二代在端上高效分類模型 MobileNet V2 上可每秒處理超過 700 張圖片,功耗僅為 2W;使用地平線工具鏈優化后的 yolo3(調整網絡結構重訓)在相近的精度下,旭日二代每秒可以處理超過 40 張圖片(是業內標稱 4TOPS AI 芯片運行公版 yolo3 的近兩倍性能)。

  旭日二代不僅性能強大,而且好用易用,主要體現在:

  • 豐富的模型和應用示例
  • 支持 Mxnet 和 Tensorflow,2020 年初支持 pytorch 3
  • 可視化的性能分析工具
  • 快速上手的 BPU API,高度靈活的 HR Runtime API 和 Platform API,客戶可以根據需求選擇

  算法芯片協同優化,將算法演進趨勢融入 BPU 架構

  相比於單純做 AI 芯片硬件的公司和單純做 AI 軟件算法及應用的公司,地平線的獨特性在於,從創立之初就堅持走“算法+芯片”的軟硬結合道路,現如今,這已經成為科技行業的重要趨勢。

  黃暢曾在以“AI 元力,重啟未來”為主題的 AI World 2019 世界人工智能峰會上提到,“為實現軟硬件協同優化,必須判斷算法向前演進的趨勢,抓住市場最主流的算法確定芯片走向,但這不是追求單一的算法模型加速。”

  地平線提出“軟硬結合、開放賦能”,堅持算法與芯片協同優化,地平線創始人兼 CEO 余凱博士不止一次地對外表示未來 AI 競爭需要“軟硬結合”並形象的說:“如果只做硬件不做軟件,那給客戶交付的就是一塊石頭。

  此次,地平線也對重要應用場景中的關鍵算法發展趨勢進行預判,前瞻性地將其計算特點融入到計算架構的設計當中,使 AI 芯片隨着算法的演進趨勢,始終能夠保持相當高的有效利用率,從而真正意義上受益於算法創新帶來的優勢。


軟硬件協同優化,AI 效能靈活

  邊緣計算迎來全新構架變革,邊緣 AI 芯片成 AIoT 應用落地的引擎

  AI 計算可以分為雲計算、邊緣計算、端計算三個層次。他們在 AI 算力、實時性以及計算的通用性三個維度上,各有所長:

  • 雲計算面向的是最通用的計算,在所有的計算中,雲計算的時空範疇是最大的,多樣性最強,所需要的算力最高,但實時性較差,並且與場景相關性弱;雲端的數據種類也是最豐富的,可以橫跨多個維度,因而可以做複雜的認知計算和模型訓練。
  • 端計算是另外一個極端,與場景相關性最強,計算專用性非常強,追求極致效率,主要面向推理。
  • 處在中間的邊緣計算是新物種,它就像我們的脊椎一樣,連接我們的大腦(雲)和神經末梢(端)。其算力遠勝於端,同時對功耗的容忍度比端也強很多;相對於雲,其實時性更好,且可以結合具體場景進行特定優化。而 5G 技術的應用,可以大幅改善邊緣和端之間的數據帶寬和傳輸延遲,使得它能夠兼具雲和端的優勢,改變現有網絡互聯格局。

  5G 時代下的物聯網模式也將隨之而變,邊緣計算成為數據過濾器與控制閥,通過它的處理,可僅將低至萬分之一的有效數據上傳到雲端進行處理,大幅降低對於骨幹網的數據傳輸壓力。換句話說,5G 將會加快信息傳播速度,但卻無法從根本上解決數據節點的“堰塞湖”現象,這就為邊緣計算帶來了廣闊的發展空間

  在傳統互聯網時代,是端和雲的二元計算架構,數據持續向雲端轉移並被處理,端只是流量入口;但是邊緣計算的加入,帶來了新變量,它在端和雲之間,構造出一種全新的可能,其對於數據的控制力將帶來新的商業範式轉移,從技術角度講,邊緣計算具備了改造傳統互聯網計算架構的潛力,將帶來從軟件到硬件的全新構架變革

  AI on Horizon:圖像+語音,從像素集感知到時空語義建模

  地平線不斷加速邊緣 AI 芯片產品的更新迭代,以軟硬結合的一體化方案,帶來極致效能提升。基於邊緣 AI 芯片,地平線致力於打造一個多層次、多維度、多樣性的開放生態體系。

  專註邊緣計算,同時得益於算法和芯片協同優化,地平線此次面向 AIoT 客戶重點推出了以下解決方案: 

  • 地平線 HeroSpark 通行門禁考勤方案:整合 AI 芯片、算法、軟件及攝像頭模組,具備高性能、低功耗、快速集成等特點,方便客戶應用與快速落地量產,可打造具備高性能人臉識別技術的出入口門禁、 可視對講、閘道通行、辦公考勤等產品;
  •  地平線 HeroSights 智能攝像機解決方案:依託軟硬結合的邊緣 AI 芯片優勢,HeroSights 可以高性價比協助客戶實現產品形態快速落地,廣泛應用於零售、學校、工地、製造、物流、家居、交通、社區等各 AIoT 場景;
  •  地平線 Nebula 智能車載主動安全解決方案:該方案基於中國首款車規級 AI 芯片——征程二代打造, 是包括 ADAS、DMS、Face ID、語音等功能在內的全棧 AI 解決方案,具有高性能、低成本、接口靈活、支持多個硬件平台的特點,方便整車廠進行集成。

  基於旭日邊緣 AI 芯片,結合領先的深度學習算法,地平線可為客戶推出具備高性能、低功耗、快速集成等特點的智能物聯解決方案,賦能社區住宅、商業樓宇、園區、學校、工廠、企事業單位等場景。這與此次發布的一站式全場景邊緣 AI 芯片解決方案——Horizon Hero 密切相關。

  在地平線上海汽車展媒體發布活動上,余凱首次向公眾解讀了 AI on Horizon 的商業理念,他表示,“AI on Horizon,Journey Together”的理念就是:

  • 定位 Tier 2 供應商,只造武器不打仗,不碰數據,不做上層應用;
  • 芯片開放賦能,一路成就客戶;
  • 提供超高性價比,極致功耗和開放的服務。

  AI on Horizon 能力集主要是“圖像+語音”,從像素集感知,到時空語義建模。在二級結構化上,有語音識別、語音喚醒、唇語識別、聲紋識別、多模態情緒分析、活體檢測、Face-ID、人體 Re-ID、人體屬性分析;在三級結構化上,有多模態生物特徵識別、超大規模人臉識別、自動建檔、三維人體建模、跨攝像頭跟蹤、行為識別、稠密人群分析。

  BOOTPRINT X2 邊緣 AI 開發套件,降低開發者門檻

  在開發者生態方面,地平線通過工具鏈服務、與行業開放社區的形式降低開發者門檻,如地平線此次發布的 BOOTPRINT X2 邊緣 AI 開發套件,BOOTPRINT X2 邊緣 AI 開發套件是地平線加入 96Boards 社區,推出的基於 96Boards SOM 規範的邊緣 AI 開發套件。

  BOOTPRINT X2 邊緣 AI 開發套件主要具備以下功能:

  • 可支持圖像識別、檢測、分割等視覺處理功能以及離線自定義詞條等語音識別功能;
  • 接口豐富且支持介入公有雲;
  • 可滿足生態合作夥伴在智能物聯網、智能駕駛等領域的技術和原型開發、驗證評估等工作。

  開放賦能,提供 AIoT 芯片解決方案、增強語音抽取方案、邊緣 AI 智能攝像機方案等

  作為從邊緣計算中脫胎的邊緣 AI 芯片,截止目前,地平線“旭日系列”邊緣 AI 芯片已為商米、多度、小米、SK 電訊、永輝等上百家 AIoT 合作夥伴提供全面的賦能服務,覆蓋智慧城市、智慧商業、智慧社區、智慧教育、智能家居等多種應用場景。在合作過程中,推出了不少技術產品和方案。

  例如,基於地平線針對零售場景的 AIoT 芯片解決方案,商米推出了 AI 識客攝像機,該款攝像機可在本地端主動識別進店顧客並進行豐富的屬性鑒別,解決商家“看店難”問題,助力零售商的精準營銷。


商米 AI 識客攝像機

  同時,地平線還為小米一系列智能設備(主要為四款語音交互產品),提供自主研發的增強語音抽取(Enhanced Speech Extraction,簡稱 ESE)方案,助力小米音響“聽的准”,使其在複雜的噪聲環境中亦可實現隨時打斷、隨時喚醒,為用戶帶來更為精準、流暢的交互體驗。  

  另外,SK 電訊作為解決方案提供商,也整合地平線的邊緣 AI 智能攝像機方案與其自有雲平台,為零售行業提供端雲完整解決方案,加速產業升級。

  地平線將通過 Wintel 模式,成為平台型賦能者

  在技術護航下,地平線認為,其 AIoT 優勢將會助力地平線成為更具效能優勢、更強方案能力、更加開放靈活的邊緣 AI 芯片企業,在未來市場中佔據一定份額。

  • 極致的效能優勢:地平線率先提出將世界領先的深度學習算法集成在自主研發的邊緣 AI 處理器及平台上,通過為客戶提供軟硬一體化方案,發揮極致效能優勢; 
  • 完整的方案能力:地平線擁有豐富的算法樣例模型,能夠為客戶提供以芯片+算法+工具鏈為核心的完整方案,滿足多樣化場景需求; 
  • 與同類型產品相比,更加靈活高效的落地能力:  
  •  軟硬協同,高 MAC 利用率,實際任務處理表現更好; 
  • 支持新模型優化,如 MobileNet、Faster RCNN。在運行 MobileNet V2、Yolo V3 等業界領先的高效模型方面,旭日二代能夠達到甚至超過業內標稱 4TOPS 算力的 AI 芯片,而其功耗僅為 2W;
  • – 相較於市場主流旗艦 AI 芯片,地平線支持更主流的訓練框架,包括 Tensorflow、PyTorch、MXNet、ONNX、Caffe。
  • 成本優勢:可在以下方面幫助客戶降低成本:設備投入——無需購置大型服務器或佔用較大寬帶網絡; 設備運維—日常維護,更新迭代方便; 

  在此基礎之上,地平線表示未來將通過 Wintel 模式,成為平台型賦能者。“地平線的終局目標是成為邊緣人工智能平台的領導者,通過 Wintel 模式,即操作系統與處理器架構整合,成為平台型賦能者,為邊緣人工智能提供底層賦能。”

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【精選推薦文章】

平板收購,iphone手機收購,二手筆電回收,二手iphone收購-全台皆可收購

收購3c,收購IPHONE,收購蘋果電腦-詳細收購流程一覽表

高價3c回收,收購空拍機,收購鏡頭,收購 MACBOOK-更多收購平台討論專區

3c收購,鏡頭 收購有可能以全新價回收嗎?

賣IPHONE,iPhone回收,舊換新!教你怎麼賣才划算?