中國大陸公布電動車違規業者,市場趨緩?

先前北京重金支持環保車,新能源車飆速成長,人人都想分杯羹。如今當局態度驟變、開始教訓業者,接連兩天公布違規廠商名單。北京政策大轉彎,新能源車恐怕會從生機蓬勃的春天一夕轉為料峭刺骨的寒冬。

BusinessKorea、路透社報導,中國財政部8日懲處了至少五家車廠,指控他們的電動車和油電混合車計畫不實,非法取得人幣10億元補助,決定吊銷蘇州吉姆西客車製造(Suzhou Gemsea Coach Manufacturing)的生產執照,並對另外四家車廠處以罰款,其中包括中國第七大轎車廠奇瑞控股(Chery Holding)的子公司。

專家指出,這表示中國新能源車政策出現劇變,中國企業工業協會(CAAM)副秘書長Xu Yanhua說,這對車業是一大打擊,對執法有重大影響。9日北京當局再次出擊,官媒中國證券報再公布了20家違規車廠,包括日本的日產汽車(Nissan)、韓國的現代汽車、中國的吉利汽車、江淮汽車(JAC)、比亞迪(BYD)子公司等。

北京調查騙補,勢必會影響新能源車銷售,難以達到年度銷售70萬輛的目標。今年前八個月,新能源車僅售出24.5萬輛,和目標差距極大,當局又當頭澆下冷水,沒了補助誘因,車商更沒動力推出電動車,車市恐會驟然轉冷。

台灣電動車概念股包括康普、F-貿聯、和大、F-乙盛、胡連、健和興、台達電等。

北京政策急轉彎有跡可循,當局為了降低財庫負擔、促進技術發展,決定調整政策,未來擬降低補貼、拉高准入門檻,讓新能源車行業告別「野蠻生長」、迎來一輪優勝劣汰的洗牌。不過,這也意味著大陸目前超過200家的新能源車新創業者有超過9成5恐在兩年內被淘汰出局。

大陸官營的人民日報8月27日報導,由於新能源車補貼政策的激勵和准入門檻較低,行業在快速發展的同時也產生不少問題,比如重複建設、低品質、同質化產品現象嚴重,甚至出現了企業騙補的情況。對此,財政部官員透露,近期將調整新能源汽車的補貼政策。中國已在去(2015)年超越美國成為全球最大新能源車(包括電動車、插電式油電混合車以及燃料電池車)市場。

(本文內容由授權提供)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

聚甘新

001.OpenShift介紹

一 OpenShift特性

1.1 OpenShift概述


Red Hat OpenShijft Container Platform (OpenShift)是一個容器應用程序平台,它為開發人員和IT組織提供了一個雲應用程序平台,用於在安全的、可伸縮的資源上部署新應用程序,而配置和管理開銷最小。

OpenShift構建於Red Hat Enterprise Linux、Docker和Kubernetes之上,為當今的企業級應用程序提供了一個安全且可伸縮的多租戶操作系統,同時還提供了集成的應用程序運行時和庫。

OpenShift帶來了健壯、靈活和可伸縮的特性。容器平台到客戶數據中心,使組織能夠實現滿足安全性、隱私性、遵從性和治理需求的平台。不願意管理自己的OpenShift集群的客戶可以使用Red Hat提供的公共雲平台OpenShift Online。

1.2 OpenShift特性


OpenShift容器平台和OpenShift Online都是基於OpenShift Origin開源軟件項目的,該項目本身使用了許多其他開源項目,如Docker和Kubernetes。

應用程序作為容器運行,容器是單個操作系統內的隔離分區。容器提供了許多與虛擬機相同的好處,比如安全性、存儲和網絡隔離,同時需要的硬件資源要少得多,啟動和終止也更快。OpenShift使用容器有助於提高平台本身及其承載的應用程序的效率、靈活性和可移植性。

OpenShift的主要特性如下:

  • 自助服務平台:OpenShift允許開發人員使用Source-to-Image(S21)從模板或自己的源代碼管理存儲庫創建應用程序。系統管理員可以為用戶和項目定義資源配額和限制,以控制系統資源的使用。
  • 多語言支持:OpenShift支持Java、Node.js、PHP、Perl以及直接來自Red Hat的Ruby。同時也包括來自合作夥伴和更大的Docker社區的許多其他代碼。MySQL、PostgreSQL和MongoDB數據庫。Red Hat還支持在OpenShift上本地運行的中間件產品,如Apache httpd、Apache Tomcat、JBoss EAP、ActiveMQ和Fuse。
  • 自動化:OpenShift提供應用程序生命周期管理功能,當上游源或容器映像發生更改時,可以自動重新構建和重新部署容器。根據調度和策略擴展或故障轉移應用程序。
  • 用戶界面:OpenShift提供用於部署和監視應用程序的web UI,以及用於遠程管理應用程序和資源的CLi。它支持Eclipse IDE和JBoss Developer Studio插件,以便開發人員可以繼續使用熟悉的工具,並支持REST APl與第三方或內部工具集成。
  • 協作:OpenShift允許在組織內或與更大的社區共享項目。
  • 可伸縮性和高可用性:OpenShift提供了容器多租戶和一個分佈式應用程序平台,其中包括彈性,以處理隨需增加的流量。它提供了高可用性,以便應用程序能夠在物理機器宕機等事件中存活下來。OpenShift提供了對容器健康狀況的自動發現和自動重新部署。
  • 容器可移植性:在OpenShift中,應用程序和服務使用標準容器映像進行打包,組合應用程序使用Kubernetes進行管理。這些映像可以部署到基於這些基礎技術的其他平台上。
  • 開源:沒有廠商鎖定。
  • 安全性:OpenShift使用SELinux提供多層安全性、基於角色的訪問控制以及與外部身份驗證系統(如LDAP和OAuth)集成的能力。
  • 動態存儲管理:OpenShift使用Kubernetes持久卷和持久卷聲明的方式為容器數據提供靜態和動態存儲管理
  • 基於雲(或不基於雲):可以在裸機服務器、活來自多個供應商的hypervisor和大多數IaaS雲提供商上部署OpenShift容器平台。
  • 企業級:Red Hat支持OpenShift、選定的容器映像和應用程序運行時。可信的第三方容器映像、運行時和應用程序由Red Hat認證。可以在OpenShift提供的高可用性的強化安全環境中運行內部或第三方應用程序。
  • 日誌聚合和metrics:可以在中心節點收集、聚合和分析部署在OpenShift上的應用程序的日誌信息。OpenShift能夠實時收集關於應用程序的度量和運行時信息,並幫助不斷優化性能。
  • 其他特性:OpenShift支持微服務體繫結構,OpenShift的本地特性足以支持DevOps流程,很容易與標準和定製的持續集成/持續部署工具集成。

二 OpenShift架構

2.1 OpenShift架構概述


OpenShift容器平台是一組構建在Red Hat Enterprise Linux、Docker和Kubernetes之上的模塊化組件和服務。OpenShift增加了遠程管理、多租戶、增強的安全性、應用程序生命周期管理和面向開發人員的自服務接口。

OpenShift的架構:



  • RHEL:基本操作系統是Red Hat Enterprise Linux;
  • Docker:提供基本的容器管理API和容器image文件格式;
  • Kubernetes:管理運行容器的主機集群(物理或虛擬主機)。它處理描述由多個資源組成的多容器應用程序的資源,以及它們如何互連;
  • Etcd:一個分佈式鍵值存儲,Kubernetes使用它來存儲OpenShift集群中容器和其他資源的配置和狀態信息。


OpenShift在Docker + Kubernetes基礎設施之上添加了提供容器應用程序平台所需的更富豐的功能:

OpenShift-Kubernetes extensions:其它資源類型存儲在Etcd中,由Kubernetes管理。這些額外的資源類型形成OpenShift內部狀態和配置,以及由標準 Kubernetes管理的應用程序資源;

Containerized services:完成許多基礎設施功能,如網絡和授權。其中一些一直運行,另一些則按需啟動。OpenShift使用Docker和Kubernetes來實現大多數內部功能。即大多數OpenShift內部服務作為由Kubernetes管理的容器;

Runtimes and xPaaS:供開發人員使用的 base image,每個image都預配置了特定的runtime或db。xPaaS提供了一組用於JBoss中間件產品(如JBoss EAP和ActiveMQ)的 base image;

DevOps tools and user experience:OpenShift提供了Web UI和CLI管理工具,從而實現配置和監視應用程序、OpenShift服務和資源。Web和CLI工具都是由相同的REST api構建的,可供IDE和CI平台等外部工具使用。OpenShift 還可以訪問外部SCM存儲庫和容器registry,並將它們的構件引入OpenShift Cloud。

OpenShift不會向開發人員和系統管理員屏蔽Docker和Kubernetes的核心基礎設施。相反,它將它們用於內部服務,並允許將Docker和Kubernetes資源導入OpenShift集群,同時原始Docker和資源可以從OpenShift集群導出,並導入到其他基於docker的基礎設施中。

OpenShift添加到Docker + Kubernetes的主要價值是自動化開發工作流,因此應用程序的構建和部署在OpenShift集群中按照標準流程進行。開發者不需要知道底層Docker的細節。OpenShift接受應用程序,打包它,並將其作為容器啟動。

2.2 Master和nodes


OpenShift集群是一組節點服務器,它們運行容器,並由一組主服務器集中管理。服務器可以同時充當master和node,但是為了增加穩定性,這些角色通常是分開的。

OpenShift工作原理和交互視圖:




master節點運行OpenShift核心服務,如身份驗證,並未管理員提供API入口。

nodes節點運行包含應用程序的容器,容器又被分組成pod。

OpenShift master運行Kubernetes master服務和Etcd守護進程;

node運行Kubernetes kubelet和kube-proxy守護進程。

雖然在描述中通常沒有聲明,但實際上master本身也是node。

scheduler和management/replication是Kubernetes主服務,而Data Store是Etcd守護進程。

Kubernetes的調度單元是pod,它是一組共享虛擬網絡設備、內部IP地址、TCP/UDP端口和持久存儲的容器。pod可以是任何東西,從完整的企業應用程序(包括作為不同容器的每一層)到單個容器中的單個微服務。例如,一個pod,一個容器在Apache下運行PHP,另一個容器運行MySQL。

Kubernetes管理replicas來縮放pods。副本是一組共享相同定義的pod。

三 管理OpenShift

3.1 OpenShift項目及應用


除了Kubernetes的資源(如pods和services)之外,OpenShift還管理projects和users。一個projects對Kubernetes資源進行分組,以便用戶可以使用訪問權限。還可以為projects分配配額,從而限制了已定義的pod、volumes、services和其他資源。

OpenShift中沒有application的概念,OpenShift client提供了一個new-app命令。此命令在projects中創建資源,但它們都不是應用程序資源。這個命令是為標準開發人員工作流配置帶有公共資源的proiect的快捷方式。

OpenShift使用lables(標籤)對集群中的資源進行分類。默認情況下,OpenShift使用app標籤將相關資源分組到應用程序中。

3.2 使用Source-to-image構建映像


OpenShift允許開發人員使用標準源代碼管理倉庫(SCM)和集成開發環境(ide)來發布應用。

OpenShift中的source -to-lmage (S2I)流程從SCM倉庫中提取代碼,自動判斷所需的runtime,基於runtime啟動一個pod,在pod中編譯應用。

當編譯成功時,將在runtime image中添加層並形成新的image,推送進入OpenShift internal registry倉庫,接着基於這個image將創建新的pod,運行應用程序。

S2I可被視為已經內置到OpenShift中的完整的CI/CD管道。

CI/CD有不同的形式,根據具體場景表現不同。例如,可以使用外部CI工具(如Jenkins)啟動構建並運行測試,然後將新構建的映像標記為成功或失敗,將其推送到QA或生產。

3.2 管理OpenShift資源

OpenShift資源定義,如image、container、pod、service、builder、template等,都存儲在Etcd中,可以由OpenShift CLI, web控制台或REST API進行管理。

OpenShift的資源科通過JSON或YAML文件查看,並且在類似Git或版本控制的SCM中共享。OpenShift甚至可以直接從外部SCM檢索這些資源定義。

大多數OpenShift操作不需要實時響應,OpenShift命令和APIs通常創建或修改存儲在Etcd中的資源描述。Etcd然後通知OpenShift控制器,OpenShift控制器會就更改警告這些資源。

這些控制器採取行動,以便使得資源的最終態反應達到更改效果。例如,如果創建了一個新的pod資源,Kubernetes將在node上調度並啟動該pod,使用pod資源確定要使用哪個映像、要公開哪個端口,等等。或者一個模板被更改,從而指定應該有更多的pod來處理負載,OpenShift會安排額外的pod(副本)來滿足更新后的模板定義。

注意:雖然Docker和Kubernetes是OpenShift的底層,但是必須主要使用OpenShift CLi和OpenShift APls來管理應用程序和基礎設施。OpenShift增加了額外的安全和自動化功能,當直接使用Docker或Kubernetes命令和APls時,這些功能必須手動配置,或者根本不可用。因此強烈建議不要使用docker或Kubernetes的命令直接管理應用。

四 OpenShift網絡

4.1 OpenShift網絡概述


Docker網絡相對簡單,Docker創建一個虛擬內核橋接器(docker0網卡),並將每個容器網絡接口連接到它。

Docker本身沒有提供允許一個主機上的pod連接到另一個主機上的pod的方法。Docker也沒有提供嚮應用程序分配公共固定IP地址的方法,以便外部用戶可以訪問它。

但Kubernetes提供service和route資源來管理pods之間的網絡,以及從外部到pods的路由流量。service在不同pods之間提供負載均衡用於接收網絡請求,同時為service的所有客戶機(通常是其他pods)提供一個內部IP地址。

container和pods不需要知道其他pods在哪裡,它們只連接到service。route為service提供一個固定的惟一DNS名稱,使其對OpenShift集群之外的客戶端可見。

Kubernetes service和route資源需要外部(功能)插件支持。service需要軟件定義的網絡(SDN),它將在不同主機上的pod之間提供通信,route需要轉發或重定向來自外部客戶端的包到服務內部IP。

OpenShift提供了一個基於Open vSwitch的SDN,路由由分佈式HAProxy farm提供。

五 OpenShift持久性存儲

5.1 永久存儲


pod可以在一個節點上停止,並隨時在另一個節點上重新啟動。同時pod的默認存儲是臨時存儲,通過對於類似數據庫需要永久保存數據的應用不適合。

Kubernetes為管理容器的外部持久存儲提供了一個框架。Kubernetes提供了PersistentVolume資源,它可以在本地或網絡中定義存儲。pod資源可以使用PersistentVolumeClaim資源來訪問對應的持久存儲卷。

Kubernetes還指定了一個PersistentVolume資源是否可以在pod之間共享,或者每個pod是否需要具有獨佔訪問權的自己PersistentVolume。當pod移動到另一個節點時,它將保持與相同的PersistentVolumeClaim和PersistentVolumne資源的關聯。這意味着pod的持久存儲數據跟隨它,而不管它將在哪個節點上運行。

OpenShift向Kubernetes提供了多種VolumeProvider,如NFS、iSCSI、FC、Gluster或OpenStack Cinder。

OpenShift還通過StorageClass資源為應用程序提供動態存儲。使用動態存儲,可以選擇不同類型的後端存儲。後面存儲根據應用程序的需要劃分為不同的“tiers”。例如,可以定義一個名為“fast”的存儲類和另一個名為“slow”的存儲類,前者使用更高速的後端存儲,後者提供普通的存儲。當請求存儲時,最終用戶可以指定一個Persistentvolumeclaim,並使用一個註釋指定他們所需的StorageClass。

六 OpenShift高可用

6.1 OpenShift高可用概述


OpenShift平台集群的高可用性(HA)有兩個不同的方面:

OpenShift基礎設施本身的HA(即主機);

以及在OpenShift集群中運行的應用程序的HA。

默認情況下,OpenShift為master提供了完全支持的本機HA機制。

對於應用程序或“pods”,如果pod因任何原因丟失,Kubernetes將調度另一個副本,將其連接到服務層和持久存儲。如果整個節點丟失,Kubernetes會為它所有的pod安排替換節點,最終所有的應用程序都會重新可用。pod中的應用程序負責它們自己的狀態,因此它們需要自己維護應用程序狀態(如HTTP會話複製或數據庫複製)。

七 Image Streams

7.1 Image Streams


要在OpenShift中創建一個新的應用程序,除了應用程序源代碼之外,還需要一個base image(S2I builder image)。如果源代碼或image任何一個更新,就會生成一個新的image,並且基於此新image創建新的pod,同時替換舊的pod。

即當應用程序代碼發生更改時,容器映像需要更新,但如果構建器映像發生更改,則部署的pod也需要更新。

Image Streams包括由tag標識的大量的image。應用程序是針對Image Streams構建的。Image Streams可用於在創建新image時自動執行操作。構建和部署可以監視Image Streams,以便在添加新image時接收通知,並分別執行構建或部署。

OpenShift默認情況下提供了幾個Image Streams,包括許多流行的runtime和frameworks。

Image Streams tag是指向Image Streams中的image的別名。通常縮寫為istag。它包含一個image歷史記錄,表示為tag曾經指向的所有images的堆棧。

每當使用特定的istag標記一個新的或現有的image時,它都會被放在歷史堆棧的第一個位置(標記為latest)。之前tag再次指向舊的image。同時允許簡單的回滾,使標籤再次指向舊的image。 本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

聚甘新

服務設計思考:平台化

平台是一套完整的服務。也是一套內部自洽的系統。核心在於分離,業務與通用服務隔離,業務與通用功能隔離。

目標:

  • 對需求方: 快速響應。可以敏捷地進行需求迭代。

  • 對第三方業務方: 以產品的方式提供服務。所見即所得。所有功能對業務方透明。

  • 對測試方: 簡易明了的測試方式。利於自動化測試,灰度測試。

  • 對運維方: 持續集成,自動化編排,自動化部署。

  • 數據方: 提供多維度,詳盡的服務數據。可以給數據方提供簡便的數據分析。

  • 內部開發: 敏捷開發。迅速集成。

實現:

  • 如何實現需求的快速響應?
    明確的方向,清晰的邊界。確認通用語言,核心領域。敏捷開發,快速迭代。AB 測試。

  • 如何為第三方提供產品式的服務?

    所見即所得。詳盡的文檔。第三方調試平台,第三方管理平台。

  • mock 服務,自動化測試,swagger 文檔。

  • Devops,CI,DI 等持續集成,服務監控。

  • 業務數據與分析數據異構存儲。提供易於分析的數據服務。

  • 組內服務負責制度,人類最佳的合作人數是 2-3 人。所以兩人維護一個項目,一人主導,一人輔助,兩人交叉合作是一個很好的團隊合作模式。如圖形成一個網狀模式(紅色線代表主導,黑色線輔助)。這樣每一個項目都將有兩個熟悉的人。

原則

  1. 單一職責。
  2. 業務關注業務,功能關注功能。
  3. 確認邊界,確認核心領域。
  4. 所見即所得。

實施

如何推進業務開發快速響應?

  1. 抽離變化與不變。形成基礎服務

    如下面一套用戶體系,將服務抽離,將變與不變隔離。

    用戶 api: 主要提供用戶相關的接口,變化大,更偏向於業務;

    用戶中心: 主要管理用戶核心領域,變動不大,需穩定高可用的服務;

    鑒權授權中心: 變動不大,主要管理用戶憑證核心領域;

  1. 抽離通用功能。

    那些非業務的通用功能應隔離於業務之外:組件化工具化服務化

    來源監控接口限流日誌分析應用監控服務依賴配置管理系統部署等(業務人員不必關心這些功能相關的事情,只需要關注於具體的業務領域)。關注點分離。

    如上面所涉及的,從Spring Cloud的各大組件可以看出,最終的方案都將走上相近的道路。

  1. 領域上下文劃分。劃分微服務項目。業務隔離,數據去中心化。服務組件化。

    Spring cloud 技術棧:

    • 服務治理: 註冊中心,服務調用,衍生的容錯(熔斷器)
    • api 網關: 來源監控,接口限流(Spring Cloud gateway、zuul)
    • **配置中心: ** 配置管理(Apollo)
    • 自動化部署: Jenkins、docker、k8s
    • 日誌與監控: prometheus、influxdb、skywalking、elk
    • 數據可視化: druid、kylin、superset
  1. 細節管控

    接口版本管理, gitflow 管理,項目迭代 release 版本管理,標準化,敏捷開發。

歡迎關注我的公眾號。

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

聚甘新

Spring Data 教程 – Redis

1. Redis簡介

Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value 數據庫,並提供多種語言的API。Redis 是一個高性能的key-value數據庫。 redis的出現,在部分場合可以對關係數據庫起到很好的補充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。

Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹複製。存盤可以有意無意的對數據進行寫操作。由於完全實現了發布/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發布記錄。同步對讀取操作的可擴展性和數據冗餘很有幫助。

redis的key都是字符串String類型,它的value是多樣化的,如下圖:

redis數據類型 ENCODING返回的編碼 底層對應的數據結構
string int long類型的整數
string embstr embstr編碼的簡單動態字符串
string raw 簡單動態字符串
list ziplist 壓縮列表
list linkedlist 雙向鏈表
hash ziplist 壓縮列表
hash ht 字典
set intset 整數集合
set ht 字典
zset ziplist 壓縮列表
zset skiplist 跳錶

2. Redis的五種數據類型

2.1 字符串對象(String)

字符串對象的模型:

redis底層提供了三種不同的數據結構實現字符串對象,根據不同的數據自動選擇合適的數據結構。這裏的字符串對象並不是指的純粹的字符串,数字也是可以的。

  • int:當數據是long類型的整数字符串時,底層使用long類型的整數實現。這個值會直接存儲在字符串對象的ptr屬性中,同時OBJECT ENCODING為int。

  • raw:當數據為長度大於44字節的字符串時,底層使用簡單動態字符串實現,說到這裏就不得不提下redis的簡單隨機字符串(Simple Dynamic String,SDS),SDS有三個屬性,free,len和buf。free存的是還剩多少空間,len存的是目前字符串長度,不包含結尾的空字符。buf是一個list,存放真實字符串數據,包含free和空字符。針對SDS本文不做詳細介紹,歡迎點擊SDS了解。

  • embstr:當數據為長度小於44字節的字符串時,底層使用embstr編碼的簡單動態字符串實現。相比於raw,embstr內存分配只需要一次就可完成,分配的是一塊連續的內存空間。

2.2 列表對象(List)

列表對象的模型:

redis中的列表對象經常被用作消息隊列使用,底層採用ziplist和linkedlist實現。大家使用的時候當作鏈表使用就可以了。

  • ziplist

    列表對象使用ziplist編碼需要滿足兩個要求,一是所有字符串長度都小於設定值值64字節(可以在配置文件中修改list-max-ziplist-value字段改變)。二是所存元素數量小於設定值512個(可以在配置文件中修改list-max-ziplist-entries字段改變)。ziplist類似與python中的list,佔用一段連續的內存地址,由此減小指針內存佔用。

    zlbytes:占內存總數

    zltail:到尾部的偏移量

    zllen:內部節點數

    node:節點

    zlend:尾部標識

    previous_entry_length:前一節點的長度

    encoding:數據類型

    content:真實數據

    遍歷的時候會根據zlbytes和zltail直接找到尾部節點nodeN,然後根據每個節點的previous_entry_length反向遍歷。增加和刪除節點會導致其他節點連鎖更新,因為每個節點都存儲了前一節點的長度。

  • linkedlist

    linkedlist有三個屬性,head,tail和len。head指向鏈表的頭部,tail指向鏈表的尾部,len為鏈表的長度。

2.3 哈希類型對象(Hash)

哈希類型對象的模型:

redis的value類型hash類型,其實就是map類型,就是在值的位置放一個map類型的數據。大家想詳細了解一下,可以參考一下這篇文章:https://www.jianshu.com/p/658365f0abfc 。

2.4 集合對象(Set)

集合對象類型的模型:

Set類型的value保證每個值都不重複。

redis中的集合對象底層有兩種實現方式,分別有整數集合和hashtable。當所有元素都是整數且元素數小於512(可在配置文件中set-max-intset-entries字段配置)時採用整數集合實現,其餘情況都採用hashtable實現。hashtable請移駕上文鏈接查閱,接下來介紹整數集合intset。intset有三個屬性,encoding:記錄数字的類型,有int16,int32和int64等,length:記錄集合的長度,content:存儲具體數據。具體結構如下圖:

2.5 有序集合對象

有序集合對象(zset)和集合對象(set)沒有很大區別,僅僅是多了一個分數(score)用來排序。

redis中的有序集合底層採用ziplist和skiplist跳錶實現,當所有字符串長度都小於設定值值64字節(可以在配置文件中修改list-max-ziplist-value字段改變),並且所存元素數量小於設定值512個(可以在配置文件中修改list-max-ziplist-entries字段改變)使用ziplist實現,其他情況均使用skiplist實現,跳躍表的實現原理這裏偷個懶,給大家推薦一篇寫的非常好的博客,點擊查看跳躍表原理。

3. Redis的安裝

可以去官網或者中文網下載Redis。redis的windows版本現在已經不更新了,所以我們安裝redis的6.0.3版本,這個版本支持的東西很多,在此次教程中,我們只對redis的五種數據類型做解釋和學習。

官網:https://redis.io/

中文網:https://www.redis.net.cn/

本教程安裝的redis版本為6.0.3版本,redis使用C語言編寫的,CentOS7的gcc自帶版本為4.8.5,而redis6.0+需要的gcc版本為5.3及以上,所以需要升級gcc版本。

下載Linux版本的tar.gz包,解壓以後進入解壓產生的包:

cd redis-6.0.3

發現沒有bin目錄,這裏需要通過make進行安裝。

# 先檢查gcc的環境 
gcc -v 
# 查看gcc版本 
yum -y install centos-release-scl 
# 升級到9.1版本 
yum -y install devtoolset-9-gcc devtoolset-9-gcc- c++ devtoolset-9-binutils 

scl enable devtoolset-9 bash 
#以上為臨時啟用,如果要長期使用gcc 9.1的話: 
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile 
# 進入redis解壓文件 
make 
# 6.0的坑,gcc版本 9.0 以上
# 等待完畢

執行完make操作之後,就可以在redis目錄看到src目錄了。進入src目錄后就可以看到redis-serverredis-cli

這裏建議將Redis的配置文件複製,保留一份原生的配置文件。

redis的配置大家可以在網上搜一下常用的配置,在這裏給大家推薦一個常用的配置,比較詳細:

https://blog.csdn.net/ymrfzr/article/details/51362125

到這裏redis就可以啟動並且正常訪問了。

注意:一定要將redis的IP地址綁定註釋掉,允許所有的IP地址訪問,不然我們從Windows訪問就訪問不了。

註釋掉下面的這一行:

同時關閉Redis的服務保護模式,將protected-mode設置為no。如下:

4. Spring Boot 整合 Redis

  • 4.1 搭建工程,引入依賴

    搭建工程的操作我這裏就不在寫出來了。直接上pom.xml

    <!--springboot父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <dependencies>
        <!--springboot-web組件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
        <!--redis整合springboot組件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.3.0.RELEASE</version>
        </dependency>
        <!--lombok組件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>
    
  • 4.2 redis的配置

    項目的配置文件,application.yml

    butterflytri:
      host: 127.0.0.1
    server:
      port: 8080 # 應用端口
      servlet:
        context-path: /butterflytri # 應用映射
    spring:
      application:
        name: redis # 應用名稱
      redis:
        host: ${butterflytri.host} # redis地址
        port: 6379 # redis端口,默認是6379
        timeout: 10000 # 連接超時時間(ms)
        database: 0 # redis默認情況下有16個分片,這裏配置具體使用的分片,默認是0
        jedis: # 使用連接redis的工具-jedis
          pool:
            max-active: 8 # 連接池最大連接數(使用負值表示沒有限制) 默認 8
            max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制) 默認 -1
            max-idle: 8 # 連接池中的最大空閑連接 默認 8
            min-idle: 0 # 連接池中的最小空閑連接 默認 0
    

    另外還有額外的配置類RedisConfig.java

    package com.butterflytri.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    /**
     * @author: WJF
     * @date: 2020/5/24
     * @description: RedisConfig
     */
    
    @Configuration
    public class RedisConfig {
    
        /**
         * redis鍵值對的值的序列化方式:通用方式
         * @return RedisSerializer
         */
        private RedisSerializer redisValueSerializer() {
            return new GenericJackson2JsonRedisSerializer();
        }
    
        /**
         * redis鍵值對的健的序列化方式:所有的健都是字符串
         * @return RedisSerializer
         */
        private RedisSerializer redisKeySerializer() {
            return new StringRedisSerializer();
        }
    
        @Bean("redisTemplate")
        public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            redisTemplate.setKeySerializer(redisKeySerializer());
            redisTemplate.setValueSerializer(redisValueSerializer());
            return redisTemplate;
        }
    
    }
    
  • 4.3 redisTemplate的使用

    value類型的值的CRUD:

    ValueServiceImpl.java

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.ValueService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    /**
     * @author: WJF
     * @date: 2020/5/27
     * @description: ValueServiceImpl
     */
    @Service
    public class ValueServiceImpl implements ValueService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addValue(String key, Object value) {
            redisTemplate.opsForValue().set(key,value);
        }
    
        @Override
        public Object get(String key) {
            return redisTemplate.opsForValue().get(key);
        }
    
        @Override
        public Object update(String key, Object newValue) {
            return redisTemplate.opsForValue().getAndSet(key,newValue);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    }	
    

    List類型的值的CRUD:

    這裏我加了枚舉類型用來控制增加的位置,因為List類型對應的是鏈表。

    ListServiceImpl.java

    package com.butterflytri.service.impl;
    
    import com.butterflytri.enums.OpsType;
    import com.butterflytri.service.ListService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: ListServiceImpl
     */
    @Service
    public class ListServiceImpl implements ListService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addList(String key, List<Object> list, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPushAll(key, list);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPushAll(key, list);
                    break;
                default:
                    throw new RuntimeException("type不能為null");
            }
        }
    
        @Override
        public void add(String redisKey, Object value, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPush(redisKey, value);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPush(redisKey, value);
                    break;
                default:
                    throw new RuntimeException("type不能為null");
            }
        }
    
        @Override
        public List<Object> get(String key) {
            return redisTemplate.opsForList().range(key, 0, -1);
        }
    
        @Override
        public Object update(String key, Object value, Integer index) {
            Object obj = redisTemplate.opsForList().index(key, index);
            redisTemplate.opsForList().set(key,index,value);
            return obj;
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    
        @Override
        public void deleteValue(String redisKey, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPop(redisKey);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPop(redisKey);
                    break;
                default:
                    throw new RuntimeException("type不能為null");
            }
        }
    }
    

    Hash類型的值的CRUD:

    hash類型是我們使用最常用的類型。

    HashServiceImpl.java:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.HashService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Map;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: HashServiceImpl
     */
    @Service
    public class HashServiceImpl implements HashService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addHashAll(String key, Map<String, Object> value) {
            redisTemplate.opsForHash().putAll(key, value);
        }
    
        @Override
        public void addHash(String redisKey, String key, Object value) {
            redisTemplate.opsForHash().put(redisKey, key, value);
        }
    
        @Override
        public Object get(String redisKey, String key) {
            return redisTemplate.opsForHash().get(redisKey, key);
        }
    
        @Override
        public Object update(String redisKey, String key, Object value) {
            Object obj = this.get(redisKey, key);
            this.delete(redisKey,key);
            redisTemplate.opsForHash().put(redisKey, key, value);
            return obj;
        }
    
        @Override
        public void delete(String redisKey, String key) {
            redisTemplate.opsForHash().delete(redisKey, key);
        }
    
        @Override
        public void deleteAll(String redisKey) {
            redisTemplate.delete(redisKey);
        }
    }
    

    Set的值的CRUD:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.SetService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Set;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: SetServiceImpl
     */
    @Service
    public class SetServiceImpl implements SetService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
    
        @Override
        public void addAll(String key, Set<Object> set) {
            redisTemplate.opsForSet().add(key,set);
        }
    
        @Override
        public void add(String key, Object value) {
            redisTemplate.opsForSet().add(key,value);
        }
    
        @Override
        public Set<Object> findAll(String key) {
            return redisTemplate.opsForSet().members(key);
        }
    
        @Override
        public void deleteValue(String key, Object value) {
            redisTemplate.opsForSet().remove(key,value);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    }
    

    ZSet類型的值的CRUD:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.SortedSetService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.LinkedHashSet;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: SortedSetServiceImpl
     */
    @Service
    public class SortedSetServiceImpl implements SortedSetService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void add(String key, String value, Double score) {
            redisTemplate.opsForZSet().add(key, value, score);
        }
    
        @Override
        public LinkedHashSet<Object> findAll(String key) {
            return (LinkedHashSet<Object>) redisTemplate.opsForZSet().range(key,0,-1);
        }
    
        @Override
        public Long count(String key, Double scoreFrom, Double scoreTo) {
            return redisTemplate.opsForZSet().count(key,scoreFrom,scoreTo);
        }
    
        @Override
        public LinkedHashSet<Object> findByScore(String key, Double scoreFrom, Double scoreTo) {
            return (LinkedHashSet<Object>) redisTemplate.opsForZSet().rangeByScore(key,scoreFrom,scoreTo);
        }
    
        @Override
        public Long rank(String key, Object value) {
            return redisTemplate.opsForZSet().rank(key,value);
        }
    
        @Override
        public void remove(String key, String value) {
            redisTemplate.opsForZSet().remove(key,value);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    
    }
    

    redis的Java客戶端有很多,在這裏我們使用的是jedis,還有一個很好的Java語言的客戶端叫lettuce,大家可以去了解一下,Spring從不重複造輪子,只會簡化輪子的使用,redisTemplate就是一個超級簡單的使用實現。到這裏redis整合Spring Boot 就結束了。

5. 項目地址

本項目傳送門:

  • GitHub —> spring-data-redis
  • Gitee —> spring-data-redis

此教程會一直更新下去,覺得博主寫的可以的話,關注一下,也可以更方便下次來學習。

  • 作者:Butterfly-Tri
  • 出處:Butterfly-Tri個人博客
  • 版權所有,歡迎保留原文鏈接進行轉載

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

聚甘新

氣候模擬:廣設風光發電 有助撒哈拉沙漠綠化

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

聚甘新

特斯拉自駕車晶片 傳將改由三星代工

三星搶攻車用晶片商機再下一成,產業界消息傳出,三星電子成功打入特斯拉電動車供應鏈,雙方已簽署特殊應用晶片(ASIC)代工合約。

按照合約內容,三星將按特斯拉的特殊規格,量身設計、生產客製化系統單晶片(SOC),將應用於無人駕駛車上。據估計,三星從晶片開發到量產,須要約三年時間。(韓國經濟日報)

此前,特斯拉自駕車晶片都是由以色列Mobileye所提供,但今年五月特斯拉電動車主在自駕模式出了意外身亡,才讓特斯拉動了尋找替代供應商的念頭。

另外,三星正在考慮將旗下系統LSI部門分拆成設計與代工兩個事業單位,原因是顧慮到特斯拉擔心三星可能將晶片設計應用在自家產品上。

(本文內容由 授權提供。照片來源: shared by CC 2.0)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

聚甘新

TESLA超級充電站持續升級,目標5~10分鐘充飽電

為提升Model 電動車的的競爭力,Tesla 將在2017 年升級超級充電站,充電裝置的功率將遠超350kW,電動車的充電時間將大幅縮短。

電動車的續航里程一直是消費者選購這類車款時主要擔心的問題,長途行駛必須選擇有充電站的路線,電動車製造商Tesla 投資建設了龐大的超級充電站體系,目前該公司共有769 個超級充電站。

Tesla 將在2017 年大幅升級超級充電站,第三代超級充電站將兩線,該公司CEO Elon Musk 在被問及新一代超級充電站的功率是否會超過350kW 時,他回應稱,僅僅只有350kW?那是兒童玩具!

目前Tesla 最新的充電站功率為145kW,功率大幅提升將有效地縮短電動車的充電時間,Tesla CTO JB Straubel 在2012 年時表示,Tesla 超級充電站的目標是讓電動車的充電時間縮短到5 到10 分鐘之內。第三代超級充電站有望實現這一目標。

超大功率並不是第三代超級充電站的唯一特點,還將推出機器人蛇形電纜自動充電功能,使用者不需要下車就能夠完成充電。

(本文由《》授權提供)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

聚甘新

最新研究:全球「水塔」面臨多重威脅 喜馬拉雅列亞洲最脆弱

摘錄自2019年12月10日中新網北京報導

據中國科學院青藏高原研究所消息,括中國科學家在內的全球科學家對被稱為「水塔」—地球78個高山冰川水系統的最新研究評估顯示,全球「水塔」正面臨氣候變化、人口增長、水資源管理不善、其他地緣政治因素等多重威脅,形勢岌岌可危。

這項最新評估研究由全球32位科學家合作撰寫,獲得中科院院士、冰川學家姚檀棟牽頭的中科院專項資助,並發表於《自然》期刊。

地球78個基於高山冰川的水系統被稱為高山「水塔」,其通過冰川、積雪、湖泊和河流來儲藏與運送水,為全球19億人(約佔全球總人口的1/4)提供水資源。亞洲以印度河「水塔」受依賴度最高也最為脆弱,它由喜馬拉雅山脈的廣大地區組成,覆蓋阿富汗、中國、印度和巴基斯坦部分地區。

姚檀棟提醒說,如果全球氣溫升幅超過攝氏2度,亞洲「水塔」氣溫則會劇增至4度,到2060-2070年會出現更大規模的冰川退卻。冰川消減後,以季節性冰川融水補給為主的河流能夠提供的淡水量也會隨之減少,下游地區人口可能會面臨淡水資源減少的問題。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

龍芯團隊完成CoreCLR MIPS64移植,已在github開源

國產龍芯的軟件生態之中.NET不會缺席,畢竟 C# 與 .NetCore/Mono 也是全球幾大主流的編程語言和運行平台之一,最近一段時間聽到太多的鼓吹政務領域不支持.NET, 大家都明白這是某些人為了自己的利益打壓使用.NET技術的公司,我今天寫這篇文章就是想通過龍芯團隊的行動告訴更多人一起來推動.NET技術在中國的發展。希望龍芯廠商、支持龍芯的國產操作系統廠商能高度重視這個問題,主動加入 .Net Core 社區,加入.NET基金會,积極貢獻代碼,儘快做好適配工作。

龍芯團隊一直在做net core的mips64移植工作,2020年6月18日完成了里程碑性的工作,在.NET Core 3.1分支上完成了MIPS64 的移植工作,目前已經在github上開源,開源地址:https://github.com/gsvm/coreclr 。具體說明可以參見 https://github.com/dotnet/runtime/issues/38069。 龍芯團隊正在做移植后的測試工作,已經完成了 9500 多項測試,ASP.NET Core示例程序 FlightFinder 已經可以在MIPS64 上正常運行,具體可以參看 https://github.com/dotnet/runtime/issues/4234。

龍芯團隊還在github上面為龍芯.NET 建立了一個倉庫 https://github.com/gsvm/loongson-dotnet,用於關於龍芯的.NET信息,工作和下載,開源協議採用和.NET Core一樣的MIT協議。 根據這個倉庫的信息,龍芯團隊將在不久的將來發布.NET Core 3.1版本,然後升級到https://github.com/dotnet/runtime ,也就是.NET 5了。目前這項工作正在緊鑼密鼓的進行,非常歡迎大家的積极參与貢獻,包括issue或者PR,如果您有任何問題或需要任何支持,請隨時提交問題或通過电子郵件:aoqi@loongson.cn 與龍芯團隊聯繫。

在文章的最後,我向你分享一個龍芯團隊成員 xiangzhai 在這個 https://github.com/xiangzhai/mono/issues/2 提到了指令集相關的編程的一些相關知識:

OpenJDK、CorelCLR、mono都太大了,比較小的虛擬機例子可以看看PSP模擬器: https://github.com/xiangzhai/ppsspp-jit-mips64/commits/mips64-port-dev

CoreCLR官方的文檔不錯:下降、寄存器分配、代碼生成 https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/jit/ryujit-overview.md

CoreCLR代碼生成常用調試方法: dotnet/runtime#606

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

Thunk函數的使用

Thunk函數的使用

編譯器的求值策略通常分為傳值調用以及傳名調用,Thunk函數是應用於編譯器的傳名調用實現,往往是將參數放到一個臨時函數之中,再將這個臨時函數傳入函數體,這個臨時函數就叫做Thunk 函數。

求值策略

編譯器的求值策略通常分為傳值調用以及傳名調用,在下面的例子中,將一個表達式作為參數進行傳遞,傳值調用以及傳名調用中實現的方式有所不同。

var x = 1;

function s(y){
    console.log(y + 1); // 3
}

s(x + 1);

在上述的例子中,無論是使用傳值調用還是使用傳名調用,執行的結果都是一樣的,但是其調用過程不同:

  • 傳值調用:首先計算x + 1,然後將計算結果2傳遞到s函數,即相當於調用s(2)
  • 傳名調用:直接將x + 1表達式傳遞給y,使用時再計算x + 1,即相當於計算(x + 1) + 1

傳值調用與傳名調用各有利弊,傳值調用比較簡單,但是對參數求值的時候,實際上還沒用到這個參數,有可能造成沒有必要的計算。傳名調用可以解決這個問題,但是實現相對來說比較複雜。

var x = 1;

function s(y){
    console.log(y + 1); // 3
}

s(x + 1, x + 2);

在上面這個例子中,函數s並沒有用到x + 2這個表達式求得的值,使用傳名調用的話只將表達式傳入而並未計算,只要在函數中沒有用到x + 2這個表達式就不會計算,使用傳值調用的話就會首先將x + 2的值計算然後傳入,如果沒有用到這個值,那麼就多了一次沒有必要的計算。Thunk函數就是作為傳名調用的實現而構建的,往往是將參數放到一個臨時函數之中,再將這個臨時函數傳入函數體,這個臨時函數就叫做Thunk 函數。

var x = 1;

function s(y){
    console.log(y + 1); // 3
}

s(x + 1);

// 等同於

var x = 1;

function s(thunk){
    console.log(thunk() + 1); // 3
}

var thunk = function(){
    return x + 1;
}

s(thunk);

Js中的Thunk函數

Js中的求值策略是是傳值調用,在Js中使用Thunk函數需要手動進行實現且含義有所不同,在Js中,Thunk函數替換的不是表達式,而是多參數函數,將其替換成單參數的版本,且只接受回調函數作為參數。

// 假設一個延時函數需要傳遞一些參數
// 通常使用的版本如下
var delayAsync = function(time, callback, ...args){
    setTimeout(() => callback(...args), time);
}

var callback = function(x, y, z){
    console.log(x, y, z);
}

delayAsync(1000, callback, 1, 2, 3);

// 使用Thunk函數

var thunk = function(time, ...args){
    return function(callback){
        setTimeout(() => callback(...args), time);
    }
}

var callback = function(x, y, z){
    console.log(x, y, z);
}

var delayAsyncThunk = thunk(1000, 1, 2, 3);
delayAsyncThunk(callback);

實現一個簡單的Thunk函數轉換器,對於任何函數,只要參數有回調函數,就能寫成Thunk函數的形式。

var convertToThunk = function(funct){
  return function (...args){
    return function (callback){
      return funct.apply(this, args);
    }
  };
};

var callback = function(x, y, z){
    console.log(x, y, z);
}

var delayAsyncThunk = convertToThunk(function(time, ...args){
    setTimeout(() => callback(...args), time);
});

thunkFunct = delayAsyncThunk(1000, 1, 2, 3);
thunkFunct(callback);

Thunk函數在ES6之前可能應用比較少,但是在ES6之後,出現了Generator函數,通過使用Thunk函數就可以可以用於Generator函數的自動流程管理。首先是關於Generator函數的基本使用,調用一個生成器函數並不會馬上執行它裏面的語句,而是返回一個這個生成器的迭代器iterator 對象,他是一個指向內部狀態對象的指針。當這個迭代器的next()方法被首次(後續)調用時,其內的語句會執行到第一個(後續)出現yield的位置為止,yield后緊跟迭代器要返回的值,也就是指針就會從函數頭部或者上一次停下來的地方開始執行到下一個yield。或者如果用的是yield*,則表示將執行權移交給另一個生成器函數(當前生成器暫停執行)。

function* f(x) {
    yield x + 10;
    yield x + 20;
    return x + 30;
}
var g = f(1);
console.log(g); // f {<suspended>}
console.log(g.next()); // {value: 11, done: false}
console.log(g.next()); // {value: 21, done: false}
console.log(g.next()); // {value: 31, done: true}
console.log(g.next()); // {value: undefined, done: true} // 可以無限next(),但是value總為undefined,done總為true

由於Generator函數能夠將函數的執行暫時掛起,那麼他就完全可以操作一個異步任務,當上一個任務完成之後再繼續下一個任務,下面這個例子就是將一個異步任務同步化表達,當上一個延時定時器完成之後才會進行下一個定時器任務,可以通過這種方式解決一個異步嵌套的問題,例如利用回調的方式需要在一個網絡請求之後加入一次回調進行下一次請求,很容易造成回調地獄,而通過Generator函數就可以解決這個問題,事實上async/await就是利用的Generator函數以及Promise實現的異步解決方案。

var it = null;

function f(){
    var rand = Math.random() * 2;
    setTimeout(function(){
        if(it) it.next(rand);
    },1000)
}

function* g(){ 
    var r1 = yield f();
    console.log(r1);
    var r2 = yield f();
    console.log(r2);
    var r3 = yield f();
    console.log(r3);
}

it = g();
it.next();

雖然上邊的例子能夠自動執行,但是不夠方便,現在實現一個Thunk函數的自動流程管理,其自動幫我們進行回調函數的處理,只需要在Thunk函數中傳遞一些函數執行所需要的參數比如例子中的index,然後就可以編寫Generator函數的函數體,通過左邊的變量接收Thunk函數中funct執行的參數,在使用Thunk函數進行自動流程管理時,必須保證yield后是一個Thunk函數。
關於自動流程管理run函數,首先需要知道在調用next()方法時,如果傳入了參數,那麼這個參數會傳給上一條執行的yield語句左邊的變量,在這個函數中,第一次執行next時並未傳遞參數,而且在第一個yield上邊也並不存在接收變量的語句,無需傳遞參數,接下來就是判斷是否執行完這個生成器函數,在這裏並沒有執行完,那麼將自定義的next函數傳入res.value中,這裏需要注意res.value是一個函數,可以在下邊的例子中將註釋的那一行執行,然後就可以看到這個值是f(funct){...},此時我們將自定義的next函數傳遞后,就將next的執行權限交予了f這個函數,在這個函數執行完異步任務后,會執行回調函數,在這個回調函數中會觸發生成器的下一個next方法,並且這個next方法是傳遞了參數的,上文提到傳入參數後會將其傳遞給上一條執行的yield語句左邊的變量,那麼在這一次執行中會將這個參數值傳遞給r1,然後在繼續執行next,不斷往複,直到生成器函數結束運行,這樣就實現了流程的自動管理。

function thunkFunct(index){
    return function f(funct){
        var rand = Math.random() * 2;
        setTimeout(() => funct({rand:rand, index: index}), 1000)
    }
}

function* g(){ 
    var r1 = yield thunkFunct(1);
    console.log(r1.index, r1.rand);
    var r2 = yield thunkFunct(2);
    console.log(r2.index, r2.rand);
    var r3 = yield thunkFunct(3);
    console.log(r3.index, r3.rand);
}

function run(generator){
    var g = generator();

    var next = function(data){
        var res = g.next(data);
        if(res.done) return ;
        // console.log(res.value);
        res.value(next);
    }

    next();
}

run(g);

每日一題

https://github.com/WindrunnerMax/EveryDay

參考

https://www.jianshu.com/p/9302a1d01113
https://segmentfault.com/a/1190000017211798
http://www.ruanyifeng.com/blog/2015/05/thunk.html

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

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

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

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化