提前達陣!現代H1環保車銷量倍增、超越本田躍居第二

韓聯社22日報導,根據市場調查公司IHS以及汽車業界指出,2017年1到6月(H1)期間南韓現代汽車(Hyundai Motor)及其子公司起亞汽車(Kia)的環保車合計銷售量達10萬2,480台、較去年同期飆增1.3倍,半年度別銷售量創下歷史新高紀錄、且已逼近去年一整年的銷售水準。

其中,H1期間現代電動車銷售量年增151.7%、插電式油電混合車年增136.4%、油電混合車年增123.7%。

銷售量暴增,也激勵現代H1期間在全球環保車市場上正式超越本田(Honda)成為全球環保車二車、僅次於豐田汽車(Toyota)。現代汽車原先計畫要在2020年結束前成為全球環保車二哥,而該計畫已提前約3年時間達成。

在油電混合車市場上,現代在H1期間超越本田躍居全球第2大廠、僅輸給豐田;在電動車市場上,去年現代銷售量僅排在第11位,不過今年H1期間躍升至第6位,落後給雷諾、特斯拉(Tesla)、北京汽車(BAIC)、眾泰汽車(Zotye)和比亞迪(BYD)。

現代汽車8月17日在首爾公開了新型燃料電池車,並預計於2018年初開賣。和現代汽車現行燃料電池車Tucson相比,新型燃料電池車的氫燃料電池系統的效率、性能、耐久性、儲存容量都有劃時代的提升,充填一次氫燃料所能行駛的距離可較現行的415公里大幅提升約四成至580公里,且預定將搭載先進駕駛輔助系統(Advanced Driver Assistance Systems;ADAS)。

現代汽車並宣布,計畫在2020年結束前將環保車車款數量自現行的14款倍增至31款,其中油電混合車為10款、插電式油電混合車11款、電動車8款、燃料電池車2款,目標是在全球環保車市場上成為僅次於日本豐田的第二大廠。

(本文內容由授權使用。圖片出處:)

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

【其他文章推薦】

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

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

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

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

特斯拉將在9 月發表電動半掛卡車,充電後可行駛300 英里

馬斯克(Elon Musk)先前曾在推特表示,特斯拉將在9 月發表載貨用的全電動半掛卡車(Tesla Semi)原型,近期路透社報導披露了一些內容,讓有興趣的人能夠一窺其細節。

在馬斯克宣布要打造全電動重型卡車後,業界一直就對其負載量和續航力有所質疑,畢竟美國一些跑長途的柴油半掛卡車滿油續航力可以到達1,000 英里(約1,610 公里)左右,要能夠與之競爭還是有些困難。

 

Tesla Semi truck unveil set for September. Team has done an amazing job. Seriously next level.

— Elon Musk (@elonmusk)

 

如今答案揭曉了,特斯拉似乎沒有打算一開始就與這些超長程的卡車競爭。

邁阿密貨運公司Ryder System 今年稍早時曾與特斯拉進行技術討論,執行長Scott Perry 向路透社透露,Tesla Semi 是沒有臥鋪的日間車(day cab),續航里程約為200~300 英里(約322~483 公里),與一般長程重型卡車仍有著些許差距,但仍可以稱得上是長程卡車「入門款」。

對於半掛卡車的續航力,特斯拉並不願意做出評論,但它們先前確實曾經表示正在與潛在客戶直接合作,針對電動半掛卡車的開發需求進行交流。

雖然傳聞的Tesla Semi 原型似乎與一般柴油半掛卡車的續航力還有些許差距,但如果真的能夠順利做出並交付,還是有著一定的應用空間。數據分析公司Fleet Complete 策略總監Sandeep Kar 指出,從統計數據來看,美國約有30% 卡車的工作範圍是在100~200 英里之間(約161~322 公里)。

除此之外,相較汽柴油車的引擎,電動車的電動機維護需求較少,電力也比柴油更加的便宜,這些都很有可能吸引到希望降低排放量和營運成本的運輸公司。

但專家指出,對於橫跨各地的載運卡車來說,目前充電站仍不夠普及,而且需要的電池體積、重量將會擠壓到能夠附載的貨物空間。

Ryder System 和其客戶都認為,電動卡車的本體成本可能會比柴油車高出許多,但維護成本將會非常便宜,燃料成本也可以預測,在電池越來越便宜、環保監管越來越嚴格的情況下,電動卡車可能會逐漸出現增長。

(合作媒體:。圖片出處:public domain CC0)

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

【其他文章推薦】

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

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

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

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

CSS如何設置列表樣式屬性,看這篇文章就夠用了

列表樣式屬性

  • HTML中有2種列表、無序列表和有序列表,在工作中無序列表比較常用,無序列表就是ul標籤和li標籤組合成的稱之為無序列表,那什麼是有序列表呢?就是ol標籤和li標籤組合成的稱之為有序列表,列表的基礎知識就簡單說明下,本章內容主要說明的是如何給列表設置樣式,若有不懂列表是什麼的園友筆者建議去進行學習。
  • 列表樣式常用的屬性有4種如:list-style-typelist-style-positionlist-style-imagelist-style,在這裏就是簡單說明下列表常用的屬性名稱而已,具體使用或每一個屬性值的介紹,在下面會具體的說明,愛學習的園友不用擔心哦。

list-style-type屬性

  • list-style-type屬性作用:就是設置列表前面項目符號的類型。
  • list-style-type屬性值說明表。
屬性值 描述
none 將列表前面項目符號去除掉。
disc 將列表前面項目符號設置為實心圓。
circle 將列表前面項目符號設置為空心圓。
square 將列表前面項目符號設置為實心小方塊。

屬性值為none使用方式

  • 讓我們進入列表的list-style-type屬性值為none實踐,實踐內容如:使用class屬性值為.box將列表前面項目符號去除掉。
  • 我們在實踐列表的list-style-type屬性值為none之前看看列表前面項目符號是什麼,讓初學者有一個直觀的印象。

  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>列表的list-style-type屬性值為none實踐</title>
</head>
  
<body>
    <ul>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
</body>
</html>
  • 結果圖

  • 現在愛學習的園友們知道了什麼是列表前面的項目符號了,那我們就進入列表的list-style-type屬性值為none實踐咯。

  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>列表的list-style-type屬性值為none實踐</title>
    <style>
        .box{
            list-style-type: none;
        }
    </style>
</head>
  
<body>
    <ul class="box">
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
</body>
</html>
  • 結果圖

  • 既然能看到這裏說明園友已經掌握了,列表的list-style-type屬性值為none使用,恭喜恭喜恭喜。

屬性值為disc使用方式

  • 在這裏說明下列表的list-style-type屬性值為disc,列表的list-style-type屬性值默認就是disc,如果是細心的園友已經發現了,上面有現成的列子在這裏就不過多的介紹了,這個屬性值為disc就跳過了哈。

屬性值為circle使用方式

  • 讓我們進入列表的list-style-type屬性值為circle實踐,實踐內容如:將列表前面的項目符號設置為空心圓。
  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>列表的list-style-type屬性值為circle實踐</title>
    <style>
        .box{
            list-style-type: circle;
        }
    </style>
</head>
  
<body>
    <ul class="box">
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
</body>
</html>
  • 結果圖

屬性值為square使用方式

  • 讓我們進入列表的list-style-type屬性值為square實踐,實踐內容如:將列表前面項目符號設置為實心方塊。
  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>列表的list-style-type屬性值為square實踐</title>
    <style>
        .box{
            list-style-type: square;
        }
    </style>
</head>
  
<body>
    <ul class="box">
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
</body>
</html>
  • 結果圖

list-style-position屬性

  • list-style-position屬性作用:設置列表前面項目符號的位置,list-style-position屬性有2個屬性值,分別是outsideinside,具體說明看下面的屬性值說明表。

list-style-position屬性值說明表

屬性值 描述
outside 將列表前面項目符號設置在外面。
inside 將列表前面項目符號設置在裏面。

屬性值為outside使用方式

  • 在實踐list-style-position屬性值為outside之前,我們先看看列表前面的項目符號的默認位置在哪,筆者為了讓初學者有一個直觀的印象,筆者將HTML頁面中的ul標籤li標籤設置了一些樣式。
  • ul標籤樣式如::width寬度設置為300px像素、height高度為150px像素、border邊框為(1px像素、显示是實線、邊框顏色為藍色)、樣式。
  • ul標籤中的li標籤設置樣式如:width寬度設置為280px像素、height高度為30px像素line-height行高為30px像素、border邊框為(1px像素、显示是實線、邊框顏色為紅色)、樣式。
  • 如果園友沒有掌握border邊框的知識,愛學習的園友不用擔心以後會寫border邊框的文章,若有想了解border邊框知識的園友可以去進行學習。

  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>屬性值為outside使用方式</title>
    <style>
        ul {
            width: 300px;
            height: 150px;
            border: 1px solid #00F;
        }
         ul li {
          
            width: 280px;
            height: 30px;
            line-height: 30px;
            border: 1px solid red;
        }
 
    </style>
</head>
  
<body>
    <ul>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
   
</body>
</html>
  • 結果圖

  • 現在大家應該很清楚的看到了列表前面項目的符號默認在ul標籤和li標籤之間的位置,現在我們知道了列表前面的項目符號的默認位置,那我們進行list-style-position屬性值為outside實踐了,實踐內容:將HTML頁面中的列表前面的項目符號設置為外面。
  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>屬性值為outside使用方式</title>
    <style>
        ul {
            width: 300px;
            height: 150px;
            border: 1px solid #00F;
        }
         ul li {
          
            width: 280px;
            height: 30px;
            line-height: 30px;
            border: 1px solid red;
            list-style-position: outside;
        }
 
    </style>
</head>
  
<body>
    <ul>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
   
</body>
</html>
  • 結果圖

  • 注意:為什麼給列表設置了list-style-position屬性值為outside,運行結果沒有發生任何變化呢,因為列表前面的項目符號默認就在外面的位置,列表前面的項目符號外面的位置就是ul標籤和li標籤之間的位置。

屬性值為inside使用方式

  • 通過介紹list-style-position屬性值為outside,大家已經知道了列表前面項目符號外邊的位置了,接下來我們將列表前面項目符號設置在裏面咯。
  • 讓我們進入list-style-position屬性值為inside實踐,將列表前面項目符號位置設置在裏面。
  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>屬性值為inside使用方式</title>
    <style>
        ul {
            width: 300px;
            height: 150px;
            border: 1px solid #00F;
        }
         ul li {
          
            width: 280px;
            height: 30px;
            line-height: 30px;
            border: 1px solid red;
            list-style-position: inside;
        }
 
    </style>
</head>
  
<body>
    <ul>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
   
</body>
</html>
  • 結果圖

  • 注意:list-style-position屬性值為inside作用就是將列表前面項目符號位置設置在li標籤中,這就是裏面的位置。

list-style-image屬性

  • list-style-image屬性作用:將列表前面項目符號設置為一張圖片。

list-style-image屬性說明表

屬性值名稱 描述
url 設置列表前面項目符號的圖片的路徑
  • 讓我們進入list-style-image屬性的實踐,實踐內容將列表前面項目符號更換一張圖片。

  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>使用list-style-image屬性方式</title>
    <style>
        ul {
            width: 300px;
            height: 150px;
            border: 1px solid #00F;
        }
         ul li {
          
            width: 280px;
            height: 30px;
            line-height: 30px;
            border: 1px solid red;
            list-style-image: url(./img/001.png);
        }
 
    </style>
</head>
  
<body>
    <ul>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
   
</body>
</html>
  • 結果圖

  • 注意:圖片路徑一定要寫在url(./img/001.png);括號當中,不然不會被渲染的,圖片路徑可以是相對路徑也可以絕對路徑。

list-style屬性

  • list-style屬性是(list-style-type屬性、list-style-position屬性、list-style-image屬性)的一個簡寫屬性,它集成了(list-style-type屬性、list-style-position屬性、list-style-image屬性)的功能。
  • 讓我們進入 list-style屬性實踐,既然看到了這裏想必園友都已經掌握了本章的內容了。
  • 代碼塊

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>使用list-style屬性方式</title>
    <style>
        ul {
            width: 300px;
            height: 150px;
            border: 1px solid #00F;
        }
         ul li {
          
            width: 290px;
            height: 30px;
            line-height: 30px;
            border: 1px solid red;
            list-style: none inside  url(./img/001.png) ;
        }
 
    </style>
</head>
  
<body>
    <ul>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
        <li>成功不是打敗別人,而是改變自己。</li>
    </ul>
   
</body>
</html>
  • 結果圖

  • 注意:list-style屬性值可以也1個或23個,順序沒有要求,若有不明白的園友可以做個實例看看就明白了,學習就要多嘗試不要偷懶呦。

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

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

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

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

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

三大方向深化汽車產業變革 – 新能源汽車,智慧汽車,輕量化設計

隨著汽車產業的變革,新能源汽車時代已經到來,同時更具顛覆性的智慧汽車也在加速發展,汽車設計中的輕量化也成為了行業重要課題之一,這些都對整個行業的關鍵技術創新提出了更高的要求。中國新能源汽車產業已進入規模化發展新階段及政策和市場共同驅動的快速成長期,而智慧汽車也將引領智慧交通進入一個新的發展階段,智慧汽車已經超越了汽車的概念,是一種智慧出行工具的理念,隨著節能減排的深入人心及政策導向,汽車設計輕量化成為了節能減排的重要途徑之一。2017全球新能源智慧汽車大會將進行一次全面行業熱點方向及最新技術的分享。

 

2017全球新能源智慧汽車大會(第二屆上海斯圖加特汽車及動力技術國際研討會SSSAET是由上海市人民政府德國巴登符騰堡州政府上海市嘉定區人民政府指導,同濟大學斯圖加特大學主辦,上海車犇資訊技術有限公司承辦的大型會議,將於2017年的1026-27在上海隆重舉行。會議主要分為智慧汽車,新能源汽車,整車設計三個主題方向,由六大主題分論壇組成,分別為“燃料電池,動力電池,電驅動,智慧網聯,汽車設計,汽車輕量化”

 

兩天大會將會邀請來自相關政府機構嘉賓,國內外40+所著名汽車研究機構,學者,整車廠,零部件廠商參與研討,演講嘉賓由2位院士及43位國內外重量級演講嘉賓強大陣容組成(已有36位嘉賓確認,其中外籍為16位),聚集500+位的國內外行業精英參與討論。且本次會議將在投稿件中,精選40篇品質較高的優秀學術論文在同濟大學學報增刊上發表。

 

大會亮點:

最高演講規模: 2位院士,43位國內外重量級演講嘉賓

最高演講嘉賓確認率:已確認36位,外籍專家16

最具權威和專業性:40篇論文,100%EI檢索

最大規模之一:500+行業人員蒞臨;80+主機廠整車商專業人士參與

最全最新議題:3大論壇6大熱點主題全覆蓋

 

2017全球新能源智慧汽車大會(第二屆上海– 斯圖加特汽車及動力技術國際研討會)期待您的參與!如需更多會議資訊請聯繫:

 

連絡人: Latika LIU(劉小姐)

電話:021 6093 0815

郵箱:

網站: www.sssaet.com

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

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

[ASP.NET Core 3框架揭秘] 文件系統[4]:程序集內嵌文件系統

一個物理文件可以直接作為資源內嵌到編譯生成的程序集中。藉助於EmbeddedFileProvider,我們可以採用統一的編程方式來讀取內嵌的資源文件,該類型定義在 “Microsoft.Extensions.FileProviders.Embedded”這個NuGet包中。在正式介紹EmbeddedFileProvider之前,我們必須知道如何將一個項目文件作為資源內嵌入到編譯生成的程序集中。

一、將項目文件變成內嵌資源

在默認情況下,我們添加到一個.NET Core項目中的靜態文件並不會成為目標程序集的內嵌資源文件。如果需要將靜態文件作為目標程序集的內嵌文件,我們需要修改當前項目對應的.csproj文件。具體來說,我們需要按照前面實例演示的方式在.csproj文件中添加<ItemGroup>/<EmbeddedResource>元素,並利用Include屬性顯式地將對應的資源文件包含進來。當我們直接利用Visual Studio將資源文件的Build Action屬性設置為“Embedded resource”,IDE會自動幫助我們修改項目文件。

<EmbeddedResource>的Include屬性可以設置多個路徑,路徑之間採用分號(“;”)作為分隔符。以上圖所示的目錄結構為例,如果我們需要將root目錄下的四個文件作為程序集的內嵌文件,我們可以修改.csproj文件並按照如下的形式將四個文件的路徑包含進來。

<Project Sdk="Microsoft.NET.Sdk">
    ...
    <ItemGroup>
        <EmbeddedResource  
            Include="root/dir1/foobar/foo.txt;root/dir1/foobar/bar.txt;root/dir1/baz.txt;root/dir2/qux.txt"></EmbeddedResource> 
    </ItemGroup>
</Project>

除了指定每個需要內嵌的資源文件的路徑之外,我們還可以採用基於通配符“*”和“**”的Globbing Pattern表達式將一組匹配的文件批量包含進來。同樣是將root目錄下的所有文件作為程序集的內嵌文件,如下的定義方式就會簡潔得多。

<Project Sdk="Microsoft.NET.Sdk">
    ...
    <ItemGroup>
        <EmbeddedResource  Include="root/**"></EmbeddedResource> 
    </ItemGroup>
</Project>

<EmbeddedResource>除了具有一個Include屬性用來添加內嵌資源文件之外,它還具有另一個Exclude屬性負責將不符合要求的文件排除出去。還是以前面這個項目為例,對於root目錄下的四個文件,如果我們不希望文件baz.txt作為內嵌資源文件,我們可以按照如下的方式將它排除。

<Project Sdk="Microsoft.NET.Sdk">
    ...
    <ItemGroup>
        <EmbeddedResource  Include="root/**" Exclude="root/dir1/baz.txt"></EmbeddedResource> 
    </ItemGroup>
</Project>

二、讀取資源文件

每個程序集都有一個清單文件(Manifest),它的一個重要作用就是記錄組成程序集的所有文件成員。總的來說,一個程序集主要由兩種類型的文件構成,它們分別是承載IL代碼的託管模塊文件和編譯時內嵌的資源文件。針對上圖所示的項目結構,如果我們將四個文本文件以資源文件的形式內嵌到生成的程序集(App.dll)中,程序集的清單文件將會採用如下所示的形式來記錄它們。

.mresource public App.root.dir1.baz.txt
{
  // Offset: 0x00000000 Length: 0x0000000C
}
.mresource public App.root.dir1.foobar.bar.txt
{
  // Offset: 0x00000010 Length: 0x0000000C
}
.mresource public App.root.dir1.foobar.foo.txt
{
  // Offset: 0x00000020 Length: 0x0000000C
}
.mresource public App.root.dir2.qgux.txt
{
  // Offset: 0x00000030 Length: 0x0000000C
}

雖然文件在原始的項目中具有層次化的目錄結構,但是當它們成功轉移到編譯生成的程序集中之後,目錄結構將不復存在,所有的內嵌文件將統一存放在同一個容器中。如果我們通過Reflector打開程序集,資源文件的扁平化存儲將會一目瞭然。為了避免命名衝突,編譯器將會根據原始文件所在的路徑來對資源文件重新命名,具體的規則是“{BaseNamespace}.{Path}”,目錄分隔符將統一轉換成“.”。值得強調的是資源文件名稱的前綴不是程序集的名稱,而是我們為項目設置的基礎命名空間的名稱。

表示程序集的Assembly對象定義了如下幾個方法來提取內嵌資源的文件的相關信息和讀取指定資源文件的內容。GetManifestResourceNames方法幫助我們獲取記錄在程序集清單文件中的資源文件名,而另一個方法GetManifestResourceInfo則用於獲取指定資源文件的描述信息。如果我們需要讀取某個資源文件的內容,我們可以將資源文件名稱作為參數調用GetManifestResourceStream方法,該方法會返回一個讀取文件內容的Stream對象。

public abstract class Assembly
{   
    public virtual string[] GetManifestResourceNames();
    public virtual ManifestResourceInfo GetManifestResourceInfo(string resourceName);
    public virtual Stream GetManifestResourceStream(string name);
}

同樣是針對前面這個演示項目對應的目錄結構,當四個文件作為內嵌文件被成功轉移到編譯生成的程序集中后,我們可以調用程序集對象的GetManifestResourceNames方法獲取這四個內嵌文件的資源名稱。如果以資源名稱(“App.root.dir1.foobar.foo.txt”)作為參數調用GetManifestResourceStream方法,我們可以讀取資源文件的內容,具體的演示如下所示。

class Program
{
    static void Main()
    {
        var assembly = typeof(Program).Assembly;
        var resourceNames = assembly.GetManifestResourceNames();
        Debug.Assert(resourceNames.Contains("App.root.dir1.foobar.foo.txt"));
        Debug.Assert(resourceNames.Contains("App.root.dir1.foobar.bar.txt"));
        Debug.Assert(resourceNames.Contains("App.root.dir1.baz.txt"));
        Debug.Assert(resourceNames.Contains("App.root.dir2.qgux.txt")); 

        var stream = assembly.GetManifestResourceStream("App.root.dir1.foobar.foo.txt");
        var buffer = new byte[stream.Length];
        stream.Read(buffer, 0, buffer.Length);
        var content = Encoding.Default.GetString(buffer);  
        Debug.Assert(content == File.ReadAllText("App/root/dir1/foobar/foo.txt"));
    }
}

三、EmbeddedFileProvider

在對內嵌於程序集的資源文件有了大致的了解之後,針對EmbeddedFileProvider的實現原理就很好理解了。由於內嵌於程序集的資源文件採用扁平化存儲形式,所以在通過 EmbeddedFileProvider構建的文件系統中並沒有目錄層級的概念。我們可以認為所有的資源文件都保存在程序集的“根目錄”下。對於EmbeddedFileProvider構建的文件系統來說,它提供的IFileInfo對象總是對一個具體資源文件的描述,這是一個具有如下定義的EmbeddedResourceFileInfo對象。

public class EmbeddedResourceFileInfo : IFileInfo
{
    private readonly Assembly     _assembly;
    private long? _length;
    private readonly string  _resourcePath;

    public EmbeddedResourceFileInfo(Assembly assembly, string resourcePath, string name, DateTimeOffset lastModified)
    {
        _assembly = assembly;
        _resourcePath = resourcePath;
        this.Name = name;
        this.LastModified = lastModified;
    }

    public Stream CreateReadStream()
    {
        Stream stream = _assembly.GetManifestResourceStream(_resourcePath);
        if (!this._length.HasValue)
        {
            this._length = new long?(stream.Length);
        }
        return stream;
    }
    
    public bool Exists => true;
    public bool IsDirectory => false;
    public DateTimeOffset LastModified { get; }    

    public string Name { get; }
    public string PhysicalPath => null;
    public long Length
    {
        get
        {
            if (!_length.HasValue)
            {
                using (Stream stream =_assembly.GetManifestResourceStream(this._resourcePath))
                {
                    _length = stream.Length;
                }
            }
            rReturn _length.Value;
        }
    }
}

如上面的代碼片段所示,我們在創建一個EmbeddedResourceFileInfo對象的時候需要指定內嵌資源文件在清單文件的中的路徑(resourcePath)、所在的程序集、資源文件的名稱(name)和作為文件最後修改時間的DateTimeOffset對象。由於一個EmbeddedResourceFileInfo對象總是對應着一個具體的內嵌資源文件,所以它的Exists屬性總是返回True,IsDirectory屬性則返回False。由於資源文件系統並不具有層次化的目錄結構,它所謂的物理路徑毫無意義,所以PhysicalPath屬性直接返回Null。CreateReadStream方法返回的是調用程序集的GetManifestResourceStream方法返回的輸出流,而表示文件長度的Length返回的是這個Stream對象的長度。

如下所示的是 EmbeddedFileProvider的定義。當我們在創建一個EmbeddedFileProvider對象的時候,除了指定資源文件所在的程序集之外,還可以指定一個基礎命名空間。如果該命名空間沒作顯式設置,默認情況下會將程序集的名稱作為命名空間,也就是說如果我們為項目指定了一個不同於程序集名稱的基礎命名空間,那麼當創建這個EmbeddedFileProvider對象的時候必須指定這個命名空間。

public class EmbeddedFileProvider : IFileProvider
{   
    public EmbeddedFileProvider(Assembly assembly);
    public EmbeddedFileProvider(Assembly assembly, string baseNamespace);

    public IDirectoryContents GetDirectoryContents(string subpath);
    public IFileInfo GetFileInfo(string subpath);
    public IChangeToken Watch(string pattern);
}

當我們調用EmbeddedFileProvider的GetFileInfo方法並指定資源文件的邏輯名稱時,該方法會將它與命名空間一起組成資源文件在程序集清單的名稱(路徑分隔符會被替換成“.”)。如果對應的資源文件存在,那麼一個EmbeddedResourceFileInfo會被創建並返回,否則返回的將是一個NotFoundFileInfo對象。對於內嵌資源文件系統來說,根本就不存在所謂的文件更新的問題,所以它的Watch方法會返回一個HasChanged屬性總是False的IChangeToken對象。

由於內嵌於程序集的資源文件總是只讀的,它所謂的最後修改時間實際上是程序集的生成日期,所以EmbeddedFileProvider在提供EmbeddedResourceFileInfo對象的時候會採用程序集文件的最後更新時間作為資源文件的最後更新時間。如果不能正確地解析出這個時間,EmbeddedResourceFileInfo的LastModified屬性將被設置為當前UTC時間。

由於 EmbeddedFileProvider構建的內嵌資源文件系統不存在層次化的目錄結構,所有的資源文件可以視為統統存儲在程序集的“根目錄”下,所以它的GetDirectoryContents方法只有在我們指定一個空字符串或者“/”(空字符串和“/”都表示“根目錄”)時才會返回一個描述這個“根目錄”的DirectoryContents對象,該對象實際上是一組EmbeddedResourceFileInfo對象的集合。在其他情況下,EmbeddedFileProvider的GetDirectoryContents方法總是返回一個NotFoundDirectoryContents對象。

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

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

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

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

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

JS三座大山再學習(二、作用域和閉包)

作用域

JS中有兩種作用域:全局作用域|局部作用域

栗子1

console.log(name);      //undefined
var name = '波妞';
var like = '宗介'
console.log(name);      //波妞
function fun(){
    console.log(name);  //波妞
    console.log(eat)    //ReferenceError: eat is not defined
    (function(){
        console.log(like)   //宗介
        var eat = '肉'
    })()
}
fun();
  1. name定義在全局,在全局可以訪問到,所以 (2) 打印能夠正確打印;
  2. 在函數fun中,如果沒有定義name屬性,那麼會到它的父作用域去找,所以 (3) 也能正確打印。
  3. 內部環境可以通過作用域鏈訪問所有外部環境,但外部環境不能訪問內部環境的任何變量和函數。類似單向透明,這就是作用域鏈,所以 (4) 不行而 (5) 可以。

那麼問題來了,為什麼第一個打印是”undefined”,而不是”ReferenceError: name is not defined”。原理簡單的說就是JS的變量提升

變量提升:JS在解析代碼時,會將所有的聲明提前到所在作用域的最前面

栗子2

console.log(name);      //undefined
var name = '波妞';
console.log(name);      //波妞
function fun(){
    console.log(name)   //undefined
    console.log(like)   //undefined
    var name = '大西瓜';
    var like = '宗介'
}
fun();

相當於

var name;
console.log(name);      //undefined
name = '波妞';
console.log(name);      //波妞
function fun(){
    var name;
    var like;
    console.log(name)   //undefined
    console.log(like)   //undefined
    name = '大西瓜';
    like = '宗介'
    console.log(name)   //大西瓜
    console.log(like)   //宗介
}
fun();

注意:是提前到當前作用域的最前面

栗子3

printName();     //printName is not a function
var printName = function(){
    console.log('波妞')
}
printName();       //波妞

相當於

var printName;
printName();     //printName is not a function
printName = function(){
    console.log('波妞')
}
printName();       //波妞

這樣一來就好理解了,函數表達式在聲明的時候還只是個變量

栗子4

{
    var name = '波妞';
}
console.log(name)   //波妞

(function(){
    var name = '波妞';
})()
console.log(name)   //ReferenceError: name is not defined

{
    let name = '波妞';
}
console.log(name)   //ReferenceError: name is not defined

從上面的栗子可以看出,不可以草率的認為JS中var聲明的變量的作用範圍就是大括號的起止範圍,ES5並沒有塊級作用域,實質是函數作用域;ES6中有了let、const定義后,才有了塊級作用域。

栗子5

function p1() { 
    console.log(1);
}
function p2() { 
    console.log(2);
}
(function () { 
    if (false) {
        function p1() {
            console.log(3);
        }
    }else{
        function p2(){
            console.log(4)
        }
    }
    p2();
    p1()
})();       
//4
//TypeError: print is not a function

這是一個非常經典的栗子,聲明提前了,但是因為判斷條件為否,所以沒有執行函數體。所以會出現”TypeError: print is not a function”。while,switch,for同理

閉包

函數與對其狀態即詞法環境(lexical environment)的引用共同構成閉包(closure)。也就是說,閉包可以讓你從內部函數訪問外部函數作用域。在JavaScript中,函數在每次創建時生成閉包。

上面的定義來自,簡單講,閉包就是指有權訪問另一個函數作用域中變量的函數。

  • 閉包的關鍵在於:外部函數調用之後其變量對象本應該被銷毀,但閉包的存在使我們仍然可以訪問外部函數的變量對象.,
//舉個例子
function makeFunc() {
    var name = "波妞";
    function displayName() {
        console.log(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

JavaScript中的函數會形成閉包。 閉包是由函數以及創建該函數的詞法環境組合而成。這個環境包含了這個閉包創建時所能訪問的所有局部變量

在例子中,myFunc 是執行 makeFunc 時創建的 displayName 函數實例的引用,而 displayName 實例仍可訪問其詞法作用域中的變量,即可以訪問到 name 。由此,當 myFunc 被調用時,name 仍可被訪問,其值 ‘波妞’ 就被傳遞到console.log中。創建閉包最常見方式,就是在一個函數內部創建另一個函數

  • 通常,函數的作用域及其所有變量都會在函數執行結束后被銷毀。但是,在創建了一個閉包以後,這個函數的作用域就會一直保存到閉包不存在為止
//例二
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

//釋放對閉包的引用
add5 = null;
add10 = null;

從本質上講,makeAdder 是一個函數工廠 — 他創建了將指定的值和它的參數相加求和的函數。在上面的示例中,我們使用函數工廠創建了兩個新函數 — 一個將其參數和 5 求和,另一個和 10 求和。

add5 和 add10 都是閉包。它們共享相同的函數定義,但是保存了不同的詞法環境。在 add5 的環境中,x 為 5。而在 add10 中,x 則為 10。

閉包的作用域鏈包含着它自己的作用域,以及包含它的函數的作用域和全局作用域。

  • 閉包只能取得包含函數中的任何變量的最後一個值
//栗子1
function arrFun1(){
    var arr = [];
    for(var i = 0 ; i < 10 ; i++){
        arr[i] = function(){
            return i
        }
    }
    return arr
}
console.log(arrFun1()[9]());     //10
console.log(arrFun1()[1]());     //10

//栗子2
function arrFun2(){
    var arr = [];
    for(var i = 0 ; i < 10 ; i++){
        arr[i] = function(num){
            return function(){
                return num
            };
        }(i)
    }
    return arr
}
console.log(arrFun2()[9]());     //9
console.log(arrFun2()[1]());     //1

栗子 1 中,arr數組中包含10個匿名函數,每個函數都可以訪問外部的變量 i , arrFun1 執行后,其作用域被銷毀,但它的變量依然存在內存中,能被循環中的匿名函數訪問,這是的 i 為 10;

栗子 2 中,arr數組中有是個匿名函數,其匿名函數內還有匿名函數,最內層匿名函數訪問的 num 被 上一級匿名函數保存在了內存中,所以可以訪問到每次的 i 的值。

如有錯誤,請斧正

以上

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

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

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

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

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

024.掌握Pod-部署MongoDB

一 前期準備

1.1 前置條件


  • 集群部署:Kubernetes集群部署參考003——019。
  • glusterfs-Kubernetes部署:參考《附010.Kubernetes永久存儲之GlusterFS超融合部署》。

1.2 部署規劃


本實驗使用StatefulSet部署MongoDB集群,同時每個MongoDB實例使用glusterfs實現永久存儲。從而部署無單點故障、高可用、可動態擴展的MongoDB集群。

部署架構如下:

二 創建StatefulSet

2.1 創建storageclass存儲類型

  1 [root@k8smaster01 ~]# vi heketi-secret.yaml			#創建用於保存密碼的secret
  2 apiVersion: v1
  3 kind: Secret
  4 metadata:
  5   name: heketi-secret
  6   namespace: heketi
  7 data:
  8   # base64 encoded password. E.g.: echo -n "mypassword" | base64
  9   key: YWRtaW4xMjM=
 10 type: kubernetes.io/glusterfs


  1 [root@k8smaster01 heketi]# kubectl create -f heketi-secret.yaml	#創建heketi
  2 [root@k8smaster01 heketi]# kubectl get secrets -n heketi
  3 NAME                                 TYPE                                  DATA   AGE
  4 default-token-6n746                  kubernetes.io/service-account-token   3      144m
  5 heketi-config-secret                 Opaque                                3      142m
  6 heketi-secret                        kubernetes.io/glusterfs               1      3m1s
  7 heketi-service-account-token-ljlkb   kubernetes.io/service-account-token   3      143m
  8 [root@k8smaster01 ~]# mkdir mongo
  9 [root@k8smaster01 ~]# cd mongo


  1 [root@k8smaster01 heketi]# vi storageclass-fast.yaml
  2 apiVersion: storage.k8s.io/v1
  3 kind: StorageClass
  4 metadata:
  5   name: fast
  6 parameters:
  7   resturl: "http://10.254.82.26:8080"
  8   clusterid: "d96022e907f82045dcc426a752adc47c"
  9   restauthenabled: "true"
 10   restuser: "admin"
 11   secretName: "heketi-secret"
 12   secretNamespace: "default"
 13   volumetype: "replicate:3"
 14 provisioner: kubernetes.io/glusterfs
 15 reclaimPolicy: Delete
  1 [root@k8smaster01 heketi]# kubectl create -f storageclass-fast.yaml
  2 [root@k8smaster01 heketi]# kubectl get storageclasses/fast



2.2 授權ServiceAccount


本實驗2.4步驟需要使用mongo-sidecar的pod來配置管理mongo pod。

由於默認的service account僅僅只能獲取當前Pod自身的相關屬性,無法觀察到其他名稱空間Pod的相關屬性信息。如果想要擴展Pod,或者一個Pod需要用於管理其他Pod或者是其他資源對象,是無法通過自身的名稱空間的serviceaccount進行獲取其他Pod的相關屬性信息的,因此需要進行手動創建一個serviceaccount,並在創建Pod時進行定義。或者直接將默認的serviceaccount進行授權。

  1 [root@uk8s-m-01 mongo]# vi defaultaccout.yaml
  2 ---
  3 apiVersion: rbac.authorization.k8s.io/v1beta1
  4 kind: ClusterRoleBinding
  5 metadata:
  6   name: DDefault-Cluster-Admin
  7 subjects:
  8   - kind: ServiceAccount
  9     # Reference to upper's `metadata.name`
 10     name: default
 11     # Reference to upper's `metadata.namespace`
 12     namespace: default
 13 roleRef:
 14   kind: ClusterRole
 15   name: cluster-admin
 16   apiGroup: rbac.authorization.k8s.io
 17 
 18 [root@uk8s-m-01 mongo]# kubectl apply -f defaultaccout.yaml


2.3 創建headless Service

  1 [root@k8smaster01 mongo]# vi mongo-headless-service.yaml




提示:本實驗直接將headless結合在StatefulSet同一個yaml文件中,參考2.4。

2.4 創建StatefulSet

  1 [root@k8smaster01 mongo]# vi statefulset-mongo.yaml
  2 ---
  3 apiVersion: v1
  4 kind: Service
  5 metadata:
  6   name: mongo
  7   labels:
  8     name: mongo
  9 spec:
 10   ports:
 11   - port: 27017
 12     targetPort: 27017
 13   clusterIP: None
 14   selector:
 15     role: mongo
 16 ---                                  #以上為headless-service
 17 apiVersion: apps/v1beta1
 18 kind: StatefulSet
 19 metadata:
 20   name: mongo
 21 spec:
 22   serviceName: "mongo"
 23   replicas: 3
 24   template:
 25     metadata:
 26       labels:
 27         role: mongo
 28         environment: test
 29     spec:
 30       terminationGracePeriodSeconds: 10
 31       containers:
 32         - name: mongo
 33           image: mongo:3.4             #新版可能不支持smallfiles參數,因此指定為3.4版本
 34           command:
 35             - mongod
 36             - "--replSet"
 37             - rs0
 38             - "--bind_ip"
 39             - 0.0.0.0
 40             - "--smallfiles"           #使用較小的默認文件
 41             - "--noprealloc"           #禁用數據文件預分配
 42           ports:
 43             - containerPort: 27017
 44           volumeMounts:
 45             - name: mongo-persistent-storage
 46               mountPath: /data/db
 47         - name: mongo-sidecar
 48           image: cvallance/mongo-k8s-sidecar
 49           env:
 50             - name: MONGO_SIDECAR_POD_LABELS
 51               value: "role=mongo,environment=test"
 52             - name: KUBERNETES_MONGO_SERVICE_NAME
 53               value: "mongo"
 54   volumeClaimTemplates:
 55   - metadata:
 56       name: mongo-persistent-storage
 57       annotations:
 58         volume.beta.kubernetes.io/storage-class: "fast"
 59     spec:
 60       accessModes: [ "ReadWriteOnce" ]
 61       resources:
 62         requests:
 63           storage: 2Gi



釋義:

  1. 該StatefulSet定義了兩個容器:mingo和mongo-sidecar。mongo是主服務程序,mongo-sidecar是將多個mongo實例進行集群設置的工具。同時mongo-sidecar中設置了如下環境變量:


    • MONGO_SIDECAR_POD_LABELS:設置為mongo容器的標籤,用於sidecar查詢它所要管理的MongoDB集群實例。
    • KUBERNETES_MONGO_SERVICE_NAME:它的值為mongo,表示sidecar將使用mongo這個服務名來完成MongoDB集群的設置。


  1. replicas=3表示MongoDB集群由3個mongo實例組成。
  2. volumeClaimTemplates是StatefulSet最重要的存儲設置。在annotations段設置volume.beta.kubernetes.io/storage-class=”fast”表示使用名為fast的StorageClass自動為每個mongo Pod實例分配後端存儲。
  3. resources.requests.storage=2Gi表示為每個mongo實例都分配2GiB的磁盤空間。




  1 [root@k8smaster01 mongo]# kubectl create -f statefulset-mongo.yaml	#創建mongo


提示:由於國內mongo鏡像可能無法pull,建議通過VPN等方式提前pull鏡像,然後上傳至所有node節點。

  1 [root@VPN ~]# docker pull cvallance/mongo-k8s-sidecar:latest
  2 [root@VPN ~]# docker pull mongo:3.4.4
  3 [root@VPN ~]# docker save -o mongo-k8s-sidecar.tar cvallance/mongo-k8s-sidecar:latest
  4 [root@VPN ~]# docker save -o mongo_3_4_4.tar mongo:3.4.4
  5 [root@k8snode01 ~]# docker load -i mongo-k8s-sidecar.tar
  6 [root@k8snode01 ~]# docker load -i mongo.tar
  7 [root@k8snode01 ~]# docker images



創建異常可通過如下方式刪除,重新創建:

  1 kubectl delete -f statefulset-mongo.yaml
  2 kubectl delete -f mongo-headless-service.yaml
  3 kubectl delete pvc -l role=mongo


三 確認驗證

3.1 查看資源

  1 [root@k8smaster01 mongo]# kubectl get pod -l role=mongo			#查看集群pod
  2 NAME      READY   STATUS    RESTARTS   AGE
  3 mongo-0   2/2     Running   0          9m44s
  4 mongo-1   2/2     Running   0          7m51s
  5 mongo-2   2/2     Running   0          6m1s



StatefulSet會用volumeClaimTemplates中的定義為每個Pod副本都創建一個PVC實例,每個PVC的名稱由StatefulSet定義中volumeClaimTemplates的名稱和Pod副本的名稱組合而成。

  1 [root@k8smaster01 mongo]# kubectl get pvc



  1 [root@k8smaster01 mongo]# kubectl get pods mongo-0 -o yaml | grep -A 3 volumes	#查看掛載


3.2 查看mongo集群


登錄任意一個mongo Pod,在mongo命令行界面用rs.status()命令查看MongoDB集群的狀態,該mongodb集群已由sidecar完成了創建。在集群中包含3個節點 每個節點的名稱都是StatefulSet設置的DNS域名格式的網絡標識名稱:

mongo-0.mongo.default.svc.cluster.local

mongo-1.mongo.default.svc.cluster.local

mongo-2.mongo.default.svc.cluster.local

同時,可以查看每個mongo實例各自的角色(PRIMARY或SECONDARY)。

  1 [root@k8smaster01 mongo]# kubectl exec -ti mongo-0 -- mongo
  2 ……
  3 rs0:PRIMARY> rs.status()




四 集群常見管理

4.1 MongoDB擴容


運行環境過程中,若3個mongo實例不足以滿足業務的要求,可對mongo集群進行擴容。僅需要通過對StatefulSet進行scale操作,從而實現在mongo集群中自動添加新的mongo節點。

  1 [root@k8smaster01 ~]# kubectl scale statefulset mongo --replicas=4	#擴容為4個
  2 [root@k8smaster01 ~]# kubectl get pod -l role=mongo
  3 NAME      READY   STATUS    RESTARTS   AGE
  4 mongo-0   2/2     Running   0          105m
  5 mongo-1   2/2     Running   0          103m
  6 mongo-2   2/2     Running   0          101m
  7 mongo-3   2/2     Running   0          50m


4.2 查看集群成員

  1 [root@k8smaster01 mongo]# kubectl exec -ti mongo-0 -- mongo
  2 ……
  3 rs0:PRIMARY> rs.status()
  4 ……



4.3 故障自動恢復


若在系統運行過程中,某個mongo實例或其所在主機發生故障,則StatefulSet將會自動重建該mongo實例,並保證其身份(ID)和使用的數據(PVC) 不變。以下為mongo-0實例發生故障進行模擬,StatefulSet將會自動重建mongo-0實例,併為其掛載之前分配的PVC“mongo-persistent-storage-mongo-0”。新的服務“mongo-0”在重新啟動后,原數據庫中的數據不會丟失,可繼續使用。

  1 [root@k8smaster01 ~]# kubectl get pvc
  2 [root@k8smaster01 ~]# kubectl delete pod mongo-0
  3 [root@k8smaster01 mongo]# kubectl exec -ti mongo-0 -- mongo
  4 ……
  5 rs0:PRIMARY> rs.status()
  6 ……





提示:進入某個實例查看mongo集群的狀態,mongo-0發生故障前在集群中的角色為PRIMARY,在其脫離集群后,mongo集群會自動選出一個SECONDARY節點提升為PRIMARY節點(本例中為mongo-2)。重啟后的mongo-0則會成為一個新的SECONDARY節點。本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

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

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

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

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

[ch02-01] 線性反向傳播

系列博客,原文在筆者所維護的github上:,
點擊star加星不要吝嗇,星越多筆者越努力。

2.1 線性反向傳播

2.1.1 正向計算的實例

假設我們有一個函數:

\[z = x \cdot y \tag{1}\]

其中:

\[x = 2w + 3b \tag{2}\]

\[y = 2b + 1 \tag{3}\]

計算圖如圖2-4。

圖2-4 簡單線性計算的計算圖

注意這裏x, y, z不是變量,只是計算結果。w, b是才變量。因為在後面要學習的神經網絡中,我們要最終求解的是w和b的值,在這裏先預熱一下。

當w = 3, b = 4時,會得到圖2-5的結果。

圖2-5 計算結果

最終的z值,受到了前面很多因素的影響:變量w,變量b,計算式x,計算式y。常數是個定值,不考慮。

2.1.2 反向傳播求解w

求w的偏導

目前的z=162,如果我們想讓z變小一些,比如目標是z=150,w應該如何變化呢?為了簡化問題,我們先只考慮改變w的值,而令b值固定為4。

如果想解決這個問題,我們可以在輸入端一點一點的試,把w變成4試試,再變成3.5試試……直到滿意為止。現在我們將要學習一個更好的解決辦法:反向傳播。

我們從z開始一層一層向回看,圖中各節點關於變量w的偏導計算結果如下:

\[因為z = x \cdot y,其中x = 2w + 3b,y = 2b + 1\]

所以:

\[\frac{\partial{z}}{\partial{w}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{w}}=y \cdot 2=18 \tag{4}\]

其中:

\[\frac{\partial{z}}{\partial{x}}=\frac{\partial{}}{\partial{x}}(x \cdot y)=y=9\]

\[\frac{\partial{x}}{\partial{w}}=\frac{\partial{}}{\partial{w}}(2w+3b)=2\]

圖2-6 對w的偏導求解過程

圖2-6其實就是鏈式法則的具體表現,z的誤差通過中間的x傳遞到w。如果不是用鏈式法則,而是直接用z的表達式計算對w的偏導數,會是什麼樣呢?我們來試驗一下。

根據公式1、2、3,我們有:

\[z=x \cdot y=(2w+3b)(2b+1)=4wb+2w+6b^2+3b \tag{5}\]

對上式求w的偏導:

\[ {\partial z \over \partial w}=4b+2=4 \cdot 4 + 2=18 \tag{6} \]

公式4和公式6的結果完全一致!所以,請大家相信鏈式法則的科學性。

求w的具體變化值

公式4和公式6的含義是:當w變化一點點時,z會發生w的變化值的18倍的變化。記住我們的目標是讓z=150,目前在初始狀態時是162,所以,問題轉化為:當我們需要z從162變到150時,w需要變化多少?

既然:

\[ \Delta z = 18 \cdot \Delta w \]

則:

\[ \Delta w = {\Delta z \over 18}={162-150 \over 18}= 0.6667 \]

所以:

\[w = w – 0.6667=2.3333\]
\[x=2w+3b=16.6667\]
\[z=x \cdot y=16.6667 \times 9=150.0003\]

我們一下子就成功地讓z值變成了150.0003,與150的目標非常地接近,這就是偏導數的威力所在。

【課堂練習】推導z對b的偏導數,結果在下一小節中使用

2.1.3 反向傳播求解b

求b的偏導

這次我們令w的值固定為3,變化b的值,目標還是讓z=150。同上一小節一樣,先求b的偏導數。

注意,在上一小節中,求w的導數只經過了一條路:從z到x到w。但是求b的導數時要經過兩條路,如圖2-7所示:

  1. 從z到x到b
  2. 從z到y到b

圖2-7 對b的偏導求解過程

從複合導數公式來看,這兩者應該是相加的關係,所以有:

\[\frac{\partial{z}}{\partial{b}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{b}}+\frac{\partial{z}}{\partial{y}}\cdot\frac{\partial{y}}{\partial{b}}=y \cdot 3+x \cdot 2=63 \tag{7}\]

其中:

\[\frac{\partial{z}}{\partial{x}}=\frac{\partial{}}{\partial{x}}(x \cdot y)=y=9\]
\[\frac{\partial{z}}{\partial{y}}=\frac{\partial{}}{\partial{y}}(x \cdot y)=x=18\]
\[\frac{\partial{x}}{\partial{b}}=\frac{\partial{}}{\partial{b}}(2w+3b)=3\]
\[\frac{\partial{y}}{\partial{b}}=\frac{\partial{}}{\partial{b}}(2b+1)=2\]

我們不妨再驗證一下鏈式求導的正確性。把公式5再拿過來:

\[z=x \cdot y=(2w+3b)(2b+1)=4wb+2w+6b^2+3b \tag{5}\]

對上式求b的偏導:

\[ {\partial z \over \partial b}=4w+12b+3=12+48+3=63 \tag{8} \]

結果和公式7的鏈式法則一樣。

求b的具體變化值

公式7和公式8的含義是:當b變化一點點時,z會發生b的變化值的63倍的變化。記住我們的目標是讓z=150,目前在初始狀態時是162,所以,問題轉化為:當我們需要z從162變到150時,b需要變化多少?

既然:

\[\Delta z = 63 \cdot \Delta b\]

則:

\[ \Delta b = {\Delta z \over 63}={162-150 \over 63}=​0.1905 \]

所以:
\[ b=b-0.1905=3.8095 \]
\[x=2w+3b=17.4285\]
\[y=2b+1=8.619\]
\[z=x \cdot y=17.4285 \times 8.619=150.2162\]

這個結果也是與150很接近了,但是精度還不夠。再迭代幾次,應該可以近似等於150了,直到誤差不大於1e-4時,我們就可以結束迭代了,對於計算機來說,這些運算的執行速度很快。

【課題練習】請自己嘗試手動繼續迭代兩次,看看誤差的精度可以達到多少?

這個問題用數學公式倒推求解一個二次方程,就能直接得到準確的b值嗎?是的!但是我們是要說明機器學習的方法,機器並不會解二次方程,而且很多時候不是用二次方程就能解決實際問題的。而上例所示,是用機器所擅長的迭代計算的方法來不斷逼近真實解,這就是機器學習的真諦!而且這種方法是普遍適用的。

2.1.4 同時求解w和b的變化值

這次我們要同時改變w和b,到達最終結果為z=150的目的。

已知\(\Delta z=12\),我們不妨把這個誤差的一半算在w賬上,另外一半算在b的賬上:

\[\Delta b=\frac{\Delta z / 2}{63} = \frac{12/2}{63}=0.095\]

\[\Delta w=\frac{\Delta z / 2}{18} = \frac{12/2}{18}=0.333\]

  • \(w = w-\Delta w=3-0.333=2.667\)
  • \(b = b – \Delta b=4-0.095=3.905\)
  • \(x=2w+3b=2 \times 2.667+3 \times 3.905=17.049\)
  • \(y=2b+1=2 \times 3.905+1=8.81\)
  • \(z=x \times y=17.049 \times 8.81=150.2\)

【課堂練習】用Python代碼實現以上雙變量的反向傳播計算過程

容易出現的問題:

  1. 在檢查Δz時的值時,注意要用絕對值,因為有可能是個負數
  2. 在計算Δb和Δw時,第一次時,它們對z的貢獻值分別是1/63和1/18,但是第二次時,由於b和w值的變化,對於z的貢獻值也會有微小變化,所以要重新計算。具體解釋如下:

\[ \frac{\partial{z}}{\partial{b}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{b}}+\frac{\partial{z}}{\partial{y}}\cdot\frac{\partial{y}}{\partial{b}}=y \cdot 3+x \cdot 2=3y+2x \]
\[ \frac{\partial{z}}{\partial{w}}=\frac{\partial{z}}{\partial{x}} \cdot \frac{\partial{x}}{\partial{w}}+\frac{\partial{z}}{\partial{y}}\cdot\frac{\partial{y}}{\partial{w}}=y \cdot 2+x \cdot 0 = 2y \]
所以,在每次迭代中,要重新計算下面兩個值:
\[ \Delta b=\frac{\Delta z}{3y+2x} \]
\[ \Delta w=\frac{\Delta z}{2y} \]

以下是程序的運行結果。

沒有在迭代中重新計算Δb的貢獻值:

single variable: b -----
w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
delta_b=0.190476
w=3.000000,b=3.809524,z=150.217687,delta_z=0.217687
delta_b=0.003455
w=3.000000,b=3.806068,z=150.007970,delta_z=0.007970
delta_b=0.000127
w=3.000000,b=3.805942,z=150.000294,delta_z=0.000294
delta_b=0.000005
w=3.000000,b=3.805937,z=150.000011,delta_z=0.000011
delta_b=0.000000
w=3.000000,b=3.805937,z=150.000000,delta_z=0.000000
done!
final b=3.805937

在每次迭代中都重新計算Δb的貢獻值:

single variable new: b -----
w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
factor_b=63.000000, delta_b=0.190476
w=3.000000,b=3.809524,z=150.217687,delta_z=0.217687
factor_b=60.714286, delta_b=0.003585
w=3.000000,b=3.805938,z=150.000077,delta_z=0.000077
factor_b=60.671261, delta_b=0.000001
w=3.000000,b=3.805937,z=150.000000,delta_z=0.000000
done!
final b=3.805937

從以上兩個結果對比中,可以看到三點:

  1. factor_b第一次是63,以後每次都會略微降低一些
  2. 第二個函數迭代了3次就結束了,而第一個函數迭代了5次,效率不一樣
  3. 最後得到的結果是一樣的,因為這個問題只有一個解

對於雙變量的迭代,有同樣的問題:

沒有在迭代中重新計算Δb,Δw的貢獻值(factor_b和factor_w每次都保持63和18):

double variable: w, b -----
w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
delta_b=0.095238, delta_w=0.333333
w=2.666667,b=3.904762,z=150.181406,delta_z=0.181406
delta_b=0.001440, delta_w=0.005039
w=2.661628,b=3.903322,z=150.005526,delta_z=0.005526
delta_b=0.000044, delta_w=0.000154
w=2.661474,b=3.903278,z=150.000170,delta_z=0.000170
delta_b=0.000001, delta_w=0.000005
w=2.661469,b=3.903277,z=150.000005,delta_z=0.000005
done!
final b=3.903277
final w=2.661469

在每次迭代中都重新計算Δb,Δw的貢獻值(factor_b和factor_w每次都變化):

double variable new: w, b -----
w=3.000000,b=4.000000,z=162.000000,delta_z=12.000000
factor_b=63.000000, factor_w=18.000000, delta_b=0.095238, delta_w=0.333333
w=2.666667,b=3.904762,z=150.181406,delta_z=0.181406
factor_b=60.523810, factor_w=17.619048, delta_b=0.001499, delta_w=0.005148
w=2.661519,b=3.903263,z=150.000044,delta_z=0.000044
factor_b=60.485234, factor_w=17.613053, delta_b=0.000000, delta_w=0.000001
w=2.661517,b=3.903263,z=150.000000,delta_z=0.000000
done!
final b=3.903263
final w=2.661517

這個與第一個單變量迭代不同的地方是:這個問題可以有多個解,所以兩種方式都可以得到各自的正確解,但是第二種方式效率高,而且滿足梯度下降的概念。

參考資料

代碼位置

ch02, Level1

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

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

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

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

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

徹底搞懂CSS偽類選擇器:is、not

本文介紹一下Css偽類:is和:not,並解釋一下is、not、matches、any之前的關係

:not

The :not() CSS pseudo-class represents elements that do not match a list of selectors. Since it prevents specific items from being selected, it is known as the negation pseudo-class.

以上是MDN對not的解釋

單從名字上我們應該能對它有大概的認知,非選擇,排除括號內的其它元素

最簡單的例子,用CSS將div內,在不改變html的前提下,除了P標籤,其它的字體顏色變成藍色,

<div>
    <span>我是藍色</span>
    <p>我是黑色</p>
    <h1>我是藍色</h2>
    <h2>我是藍色</h2>
    <h3>我是藍色</h3>
    <h4>我是藍色</h4>
    <h5>我是藍色</h5>
</div>

之前的做法

div span,div h2,div h3, div h4,{
  color: blue;
}

not寫法

div:not(p){
  color: blue;
}

從上面的例子可以明顯體會到not偽類選擇器的作用

下面升級一下,問:將div內除了span和p,其它字體顏色變藍色

div:not(p):not(span){
  color: blue;
}

還有更為簡潔的方法,如下,但是目前兼容不太好,不建議使用

div:not(p,span){
  color: blue;
}

兼容

除IE8,目前所有主流瀏覽器都支持,可以放心使用

:is

The :is() CSS pseudo-class function takes a selector list as its argument, and selects any element that can be selected by one of the selectors in that list. This is useful for writing large selectors in a more compact form.

以上是MDN的解釋

在說is前,需要先了解一下matches

matches跟is是什麼關係?

matches是is的前世,但是本質上確實一個東西,用法完全一樣

matches這個單詞意思跟它的作用非常匹配,但是它跟not作用恰好相反,作為not的對立面,matches這個次看起來確實格格不入,而且單詞不夠簡潔,所以它被改名了,這裏還有一個issue

好了,現在知道matches和is其實是一個東西,那麼is的用法是怎樣的呢?

舉例:將header和main下的p標籤,在鼠標hover時文字變藍色

<header>
  <ul>
    <li><p>鼠標放上去變藍色</p></li>
    <li><p>鼠標放上去變藍色</p></li>
  </ul>
  <p>正常字體</p>
</header>

<main>
  <ul>
    <li><p>鼠標放上去變藍色</p></li>
    <li><p>鼠標放上去變藍色</p></li>
    <p>正常字體</p>
  </ul>
</main>

<footer>
  <ul>
    <li><p>正常字體</p></li>
    <li><p>正常字體</p></li>
  </ul>
</footer>

之前的做法

header ul p:hover,main ul p:hover{
  color: blue;
}

is寫法

:is(header, main) ul p:hover{
  color: blue;
}

從上面的例子大概能看出is的左右,但是並沒有完全體現出is的強大之處,但是當選擇的內容變多之後,特別是那種層級較多的,會發現is的寫法有多簡潔,拿MDN的一個例子看下

之前的寫法

/* Level 0 */
h1 {
  font-size: 30px;
}
/* Level 1 */
section h1, article h1, aside h1, nav h1 {
  font-size: 25px;
}
/* Level 2 */
section section h1, section article h1, section aside h1, section nav h1,
article section h1, article article h1, article aside h1, article nav h1,
aside section h1, aside article h1, aside aside h1, aside nav h1,
nav section h1, nav article h1, nav aside h1, nav nav h1 {
  font-size: 20px;
}

is寫法

/* Level 0 */
h1 {
  font-size: 30px;
}
/* Level 1 */
:is(section, article, aside, nav) h1 {
  font-size: 25px;
}
/* Level 2 */
:is(section, article, aside, nav)
:is(section, article, aside, nav) h1 {
  font-size: 20px;
}

可以看出,隨着嵌套層級的增加,is的優勢越來越明顯

說完了is,那就必須認識一下any,前面說到is是matches的替代者,

any跟is又是什麼關係呢?

是的,is也是any的替代品,它解決了any的一些弊端,比如瀏覽器前綴、選擇性能等

any作用跟is完全一樣,唯一不同的是它需要加瀏覽器前綴,用法如下

:-moz-any(.b, .c) {

}
:-webkit-any(.b, .c) {
    
}

結論

通過上面的介紹大概講述了css偽類is,not,matches,any它們三者的關係

is+not組合是大勢所趨

最後附上我的個人網站 ,轉載請著名出處

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

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

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

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

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

【故障公告】docker swarm 集群問題造成新版博客後台故障

非常抱歉,今天下午 16:55~17:05 左右,由於 docker swarm 集群的突發不穩定問題造成(目前處於灰度發布階段)無法正常使用,由此給您帶來麻煩,請您諒解。

出故障期時,新版博客後台的2個容器都無法正常啟動。

AME                NODE                DESIRED STATE       CURRENT STATE 
i_web.1             prod-swarm-w3       Running             Assigned 5 minutes ago                       
i_web.2             prod-swarm-w4       Running             Assigned 2 hours ago       

發現問題后,我們進行了刪除 stack 並重新部署的操作。

docker stack rm i
./deploy-production.sh 2.0.6
NAME                NODE                DESIRED STATE       CURRENT STATE
i_web.1             prod-swarm-w3       Running             Assigned 42 seconds ago                       
i_web.2             prod-swarm-w7       Running             Starting 42 seconds ago

重新部署后發現 prod-swarm-w7  節點上的容器可以正常啟動,而 prod-swarm-w3 節點上的容器問題依舊,由此確認是 prod-swarm-w3 節點出了問題,於是立即卸載該節點。

docker node update --availability drain prod-swarm-w3

卸載后,新版博客後台很快恢復了正常。

我們已經決定用 k8s 取代 docker swarm ,但目前 k8s 集群還沒部署好,在這即將與 docker swarm 說 88 的時刻,又被 docker swarm 坑了一次,都怪我們當時貪圖省事,選對了集裝箱(docker 容器)卻上錯了船(docker swarm),我們會深刻吸取這次上錯船的教訓。

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

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

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

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象