標籤: 南投搬家公司費用

  • 三文搞懂學會Docker容器技術(下)

    三文搞懂學會Docker容器技術(下)

    接着上面一篇:三文搞懂學會Docker容器技術(上)

                             三文搞懂學會Docker容器技術(中)

    7,Docker容器目錄掛載

      7.1 簡介

    容器目錄掛載:

    我們可以在創建容器的時候,將宿主機的目錄與容器內的目錄進行映射,這樣我們就可以實現宿主機和容器目錄的雙向數據自動同步;

      7.2 作用

    前面學過cp命令來實現數據傳遞,這種方式比較麻煩;

    我們通過容器目錄掛載,能夠輕鬆實現代碼上傳,配置修改,日誌同步等需求;

      7.3 實現

    語法:

    docker run -it -v  /宿主機目錄:/容器目錄 鏡像名

    多目錄掛載

    docker run -it -v /宿主機目錄:/容器目錄 -v /宿主機目錄2:/容器目錄2  鏡像名

    注意:

    如果你同步的是多級目錄,可能會出現權限不足的提示;

    這是因為Centos7中的安全模塊selinux把權限禁掉了,我們需要添加  –privileged=true 來解決掛載的目錄沒有權限的問題;

      7.4 掛載目錄只讀

    docker run -it -v  /宿主機目錄:/容器目錄:ro 鏡像名

     

    8,Docker遷移與備份

      8.1 概述

    我們開發的時候,經常自定義鏡像,然後commit提交成鏡像到本地倉庫,但是我們發布到客戶服務器的時候,可以用前面講得搞到hub官方,或者阿里雲,但是有些機密性的項目,是禁止公網存儲的,所以我們只能通過docker鏡像備份和遷移實現;

      8.2 實現

    備份鏡像:

    docker save -o 備份鏡像的名稱  源鏡像名稱:tag版本

     docker save -o mytomcat7.1.tar java1234/tomcat7:7.1

     

    恢復鏡像:

    docker load -i 鏡像文件

    docker load -i mytomcat7.1.tar

     

    9,DockerFile詳解

      9.1 DockerFile簡介

    Dockerfile是由一系列命令和參數構成的腳本,這些命令應用於操作系統(centos或者Ubuntu)基礎鏡像並最終創建的一個新鏡像;

    我們前面講過的用手工的方式,修改配置文件,或者添加,刪除文件目錄的方式,來構建一種新鏡像;這種手工方式麻煩,容易出錯,而且不能復用;

    我們這裏講Dockerfile,用腳本方式來構建自動化,可復用的,高效率的創建鏡像方式,是企業級開發的首選方式;

     

    再軟件系統開發生命周期中,採用Dockerfile來構建鏡像;

    1、對於開發人員:可以為開發團隊提供一個完全一致的開發環境;

    2、對於測試人員:可以直接拿開發時所構建的鏡像或者通過Dockerfile文件構建一個新的鏡像開始工作;

    3、對於運維人員:在部署時,可以實現應用的無縫移植。

      9.2 DockerFile常用指令

    FROM image_name:tag 定義了使用哪個基礎鏡像啟動構建流程
    MAINTAINER user_info 聲明鏡像維護者信息
    LABEL key value 鏡像描述元信息(可以寫多條)
    ENV key value 設置環境變量(可以寫多條)
    RUN command 構建鏡像時需要運行的命令(可以寫多條)
    WORKDIR path_dir 設置終端默認登錄進來的工作目錄
    EXPOSE port 當前容器對外暴露出的端口
    ADD source_dir/file dest_dir/file 將宿主機的文件複製到容器內,如果是一個壓縮文件,將會在複製后自動解壓
    COPY source_dir/file dest_dir/file 和ADD相似,但是如果有壓縮文件是不能解壓
    VOLUME 創建一個可以從本地主機或其他容器掛載的掛載點,一般用來存放數據庫和需要保持的數據等
    CMD 指定容器啟動時要運行的命令,假如有多個CMD,最後一個生效
    ENTRYPOINT 指定容器啟動時要運行的命令
    ONBUILD 當構建一個被繼承的Dockerfile時運行的命令,父鏡像在被子鏡像繼承後父鏡像的onbuild被觸發。可以把ONBUID理解為一個觸發器。

     

    10,Docker私有倉庫

      10.1 簡介

    Docker私有倉庫主要是企業內部用來存放鏡像的倉庫,相對官方倉庫以及阿里雲倉庫,具有更高的保密安全級別;

      10.2 私有倉庫搭建

    第一步:拉取私有倉庫鏡像 (私有倉庫程序本身就是一個鏡像)

    docker pull registry

    第二步:啟動私有倉庫容器

    docker run -di –name=myRegistry -p 5000:5000 registry

    第三步:測試

    http://192.168.1.112:5000/v2/_catalog

    看到這個 說明啟動OK。因為倉庫里還沒有鏡像,所以就是空的;

    第四步:etc/docker 修改daemon.json,讓docker信任私有倉庫地址

    “insecure-registries”: [“192.168.1.112:5000”]

     

    第五步:修改配置后重啟docker;

     systemctl restart docker

      10.3 私有倉庫測試

    第一步:標記此鏡像為私有倉庫的鏡像

    docker tag tomcat:7 192.168.1.112:5000/mytomcat7

    第二步:上傳鏡像到私有倉庫

    docker push 192.168.1.112:5000/mytomcat7

    此時私有倉庫里已經有了這個鏡像;

    第三步:刪除192.168.1.112:5000/mytomcat7本地倉庫鏡像

    docker rmi -f 192.168.1.112:5000/mytomcat7

    第四步:從私有倉庫拉取192.168.1.112:5000/mytomcat7鏡像,並運行;

    docker run -it -p 8080:8080 192.168.1.112:5000/mytomcat7

    第五步:瀏覽器運行 http://192.168.1.112:8080測試

     

    ——————————————————————————————————————————

    作者: java1234_小鋒

    出處:https://www.cnblogs.com/java688/p/13174647.html

    版權:本站使用「CC BY 4.0」創作共享協議,轉載請在文章明顯位置註明作者及出處。

    ——————————————————————————————————————————

     

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

    【其他文章推薦】

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

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

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

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?

  • 快速打造屬於你的接口自動化測試框架

    快速打造屬於你的接口自動化測試框架

    1 接口測試

    接口測試是對系統或組件之間的接口進行測試,主要是校驗數據的交換,傳遞和控制管理過程,以及相互邏輯依賴關係。
    接口自動化相對於UI自動化來說,屬於更底層的測試,這樣帶來的好處就是測試收益更大,且維護成本相對來說較低,是我們進行自動化測試的首選

    2 框架選型

    目前接口自動化的框架比較多,比如jmeter,就可以集接口自動化和性能測試於一體,該工具編寫用例效率不高;還有我們常用的postman,結合newman也可以實現接口自動化;Python+unittest+requests+HTMLTestRunner 是目前比較主流的測試框架,對python有一定的編碼要求;
    本期我們選擇robotframework(文中後續統一簡稱為RF)這一個比較老牌的測試框架進行介紹,RF是一個完全基於 關鍵字 測試驅動的框架,它即能夠基於它的一定規則,導入你需要的測試庫(例如:其集成了selenium的測試庫,即可以理解為操作控件的測試底層庫),然後基於這些測試庫,你能應用TXT形式編寫自己的關鍵字(支持python和java語言,這些關鍵字即你的庫組成),之後,再編寫(測試用例由測試關鍵字組成)進行測試;他支持移動端、UI自動化和接口自動化的測試

    3 環境搭建

    • python的安裝:目前選取的python3以上的版本,RF的運行依賴python
    • robotframework:參考https://www.jianshu.com/p/9dcb4242b8f2
    • jenkins:用於調度RF的用例執行環境
    • gitlab:代碼倉庫

    4 需求

    4.1 需求內容
    接口內容:實現一個下單,並檢查訂單狀態是否正常的場景;該需求涉及到如下三個接口

    • 下單接口
    • 訂單結果查詢接口
    • 下單必須帶上認證標識,生成token的接口

    環境覆蓋:需要支持能在多套環境運行,比如測試和預發布環境
    系統集成:需要能夠集成在CICD中,實現版本更新后的自動檢測

    4.2 用例設計
    4.2.1 用例設計,根據業務場景設計測試用例,方便後續實現

    4.2.2 測試數據構造,預置不同環境的測試數據,供實現調用

    5 整體實現架構

    接口測試實現層:在RF,通過引用默認關鍵字 RequestsLibrary (實現http請求)和通過python自定義關鍵字來完成用例實現的需求;
    jenkins調度:在jenkins上配置一個job,設置好RF用例執行的服務器和發送給服務器相關的RF執行的指令,並且在jenkins中配置好測試報告模板,這樣用例便可以通過jenkins完成執行併發送測試結果給項目干係人;
    生成用例執行的API:上圖中藍色部分,就是為了將jenkins的job生成一個可訪問api接口,方便被測項目的CICD集成;
    集成到被測系統CICD流程:將上面步驟中封裝的API配置在被測應用的__gitlab-ci.yml__中,完成整個接口自動化的閉環

    6 RF用例實現

    6.1 引用的內置關鍵字

    • RequestsLibrary 構造http的請求,get|post等請求
    getRequests
    # get請求的入參
        [Arguments]    ${url_domain}    ${getbody}    ${geturl}    ${getToken}
        Create session    postmain    ${url_domain}
    # 定義header的內容
        ${head}    createdictionary    content-type=application/json    Authorization=${getToken}    MerchantId=${s_merchant_id}
    # get請求
        ${addr}    getRequest    postmain    ${geturl}    params=${getbody}    headers=${head}
    # 請求狀態碼斷言
        Should Be Equal As Strings    ${addr.status_code}    200
        ${response_get_data}    To Json    ${addr.content}
    # 返回http_get請求結果
        Set Test Variable    ${response_get_data}	 
        Delete All Sessions
    

    6.2 自定義關鍵字

    • getEnvDomain 用於從自定義的configs.ini文件獲取對應環境的微服務的請求域名
      configs.ini的內容
    # 獲取configs.ini的內容
    import configparser
    def getEnv(path,env):
        config = configparser.ConfigParser()
        config.read(path)
        passport = config[env]['passport']
        stock=config[env]['stock']
        finance=config[env]['finance']
        SUP = config[env]['SUP']
        publicApi = config[env]['publicApi']
        publicOrder = config[env]['publicOrder']
        data_dict={'passport':passport,'stock':stock,'finance':finance,'SUP':SUP,'publicApi':publicApi,'publicOrder':publicOrder}
        return data_dict
    
    • excelTodict 用戶將excel中的內容作為字典返回
    import xlrd
    
    '''
    通用獲取excel數據
    @:param path excel文件路徑
    @:param sheet_name excel文件裏面sheet的名稱 如:Sheet1
    @:env 環境,是IT還是PRE
    '''
    def getExcelDate(path, sheet_name,env):
        bk = xlrd.open_workbook(path)
        sh = bk.sheet_by_name(sheet_name)
        row_num = sh.nrows
        data_list = []
        for i in range(1, row_num):
            row_data = sh.row_values(i)
            data = {}
            for index, key in enumerate(sh.row_values(0)):
                data[key] = row_data[index]
            data_list.append(data)
        data_list1 = []
        for x in data_list:
            #print('這是'+str(x))
            if(x.get('env')==env):
                data_list1.append(x)
        return data_list1
    
    • getToken 提供接口下單的授權token
    *** Keywords ***
    # 根據傳入的clientid、secret生成對應的token
    getToken
        [Arguments]    ${client_id}    ${client_secret}    ${url_domain}
        Create session    postmain    ${url_domain}
        ${auth}    createdictionary    grant_type=client_credentials    client_id=${client_id}    client_secret=${client_secret}
        ${header}    createdictionary    content-type=application/x-www-form-urlencoded
        ${addr}    postRequest    postmain    /oauth/token    data=${auth}    headers=${header}
        Should Be Equal As Strings    ${addr.status_code}    200
        ${responsedata}    To Json    ${addr.content}
        ${access}    Get From Dictionary    ${responsedata}    access_token
        ${token}    set variable    bearer ${access}
        Set Test Variable    ${token}
        Delete All Sessions
    
    • getAllDate 獲取該用例下的所有數據
    getAllData
        [Arguments]    ${row_no}
        getEnvDomain
        getBalance    ${row_no}
        getStockNum    ${row_no}
        getSupProPrice    ${row_no}
        getProPrice    ${row_no}
        Set Test Variable    ${publicOrderUrl}
        Set Test Variable    ${FPbalance}
        Set Test Variable    ${Pbalance}
        Set Test Variable    ${Sbalance}
        Set Test Variable    ${Jbalance}
        Set Test Variable    ${Cardnum}
        Set Test Variable    ${sprice}
        Set Test Variable    ${price}
        Set Test Variable    ${j_merchant_id}
        Set Test Variable    ${s_merchant_id}
        Set Test Variable    ${stock_id}
        Set Test Variable    ${p_product_id}
        Set Test Variable    ${s_product_id}
    
    
    • 實現demo
    *** Settings ***
    Test Template
    Resource          引用所有資源.txt
    
    *** Test Cases ***
    *** Settings ***
    Test Template
    Resource          引用所有資源.txt
    
    *** Test Cases ***
    01 下單卡密直儲商品
        [Tags]    order
        LOG    ---------------------獲取下單前的數量、餘額------------------------------------------
        getAllData    0
        ${Cardnum1}    set variable    ${Cardnum}
        ${FPbalance1}    set variable    ${FPbalance}
        ${Pbalance1}    set variable    ${Pbalance}
        ${Sbalance1}    set variable    ${Sbalance}
        ${Jbalance1}    set variable    ${Jbalance}
        ${CustomerOrderNo1}    Evaluate    random.randint(1000000, 9999999)    random
        ${Time}    Get Time
        log    ------------------------下單操作-------------------------------------------------------
        getToken    100xxxx    295dab07a9xxxx9780be0eb95xxxx   ${casUrl}
        ${input_cs}    create dictionary    memberId=${j_merchant_id}    clientId=1xxx079    userId=string    shopType=string    customerOrderNo=${CustomerOrderNo1}
        ...    productId=${p_product_id}    buyNum=1    chargeAccount=otest888888    notifyUrl=string    chargeIp=string    chargePassword=string
        ...    chargeGameName=string    chargeGameRole=string    chargeGameRegion=string    chargeGameSrv=string    chargeType=string    remainingNumber=0
        ...    contactTel=string    contactQQ=string    customerPrice=0    poundage=0    batchNumber=    originalOrderId=string
        ...    shopName=string    appointSupProductId=0    stemFromSubOrderId=123456    externalBizId=456789
        postRequests    ${publicOrderUrl}    ${input_cs}    /api/Order    ${token}
        ${data}    get from dictionary    ${responsedata}    data
        ${orderid}    get from dictionary    ${data}    id
        sleep    6
        ${getdata}    create dictionary    Id=${orderid}    PageIndex=1    PageSize=1
        getRequests    ${publicOrderUrl}    ${getdata}    /api/Order/GetList    ${token}
        ${datalist}    get from dictionary    ${response_get_data}    data
        ${data}    get from dictionary    ${datalist}    list
        ${dict}    set variable    ${data}[0]
        ${orderOuterStatus}    get from dictionary    ${dict}    orderOuterStatus
        LOG    ---------------------獲取下單后的數量、餘額----------------------------------------------
        getAllData    0
        ${Cardnum2}    set variable    ${Cardnum}
        ${FPbalance2}    set variable    ${FPbalance}
        ${Pbalance2}    set variable    ${Pbalance}
        ${Sbalance2}    set variable    ${Sbalance}
        ${Jbalance2}    set variable    ${Jbalance}
        ${sprice}    set variable    ${sprice}
        ${price}    set variable    ${price}
        log    ------------------斷言-----------------------------------------------------------------
        ${Cardnum3}    Evaluate    ${Cardnum1}
        ${Jbalance3}    Evaluate    ${Jbalance1}
        ${Sbalance3}    Evaluate    ${Sbalance1}
        ${Pbalance3}    Evaluate    ${Pbalance1}
        should be true    ${orderOuterStatus}==90
        should be true    ${Cardnum3}==${Cardnum2}
        should be true    ${Jbalance3}==${Jbalance2}
        should be true    ${Sbalance3}==${Sbalance2}
        should be true    ${Pbalance3}==${Pbalance2}
    
    

    7 集成到CICD流程

    7.1 jenkins配置job
    通過jenkins的參數化構建,定義it和pre兩套環境

    jenkins發送RF執行的命令

    7.2 封裝的jenkins_job的執行接口地址
    通過python的flask框架,根據測試和pre兩套環境包一層jenkins的job執行接口

    __author__ = 'paul'
    
    # !/usr/bin/env python
    # -*- coding: utf-8 -*-
    from flask import Flask, abort, request, jsonify
    import jenkins
    
    server = jenkins.Jenkins('http://10.0.1.xxx:80', username='xxx', password='fuluxxxx')
    
    app = Flask(__name__)
    
    tasks = []
    
    # it的測試集合http請求接口
    @app.route('/test/it', methods=['get'])
    def robot_Test_It():
        server.build_job('CI_FuluOrder', {'environment': 'IT'})
        return jsonify({'result': 'success'})
    
    # pre的測試集合http請求接口
    @app.route('/test/pre', methods=['get'])
    def robot_Test_Pre():
        server.build_job('CI_FuluOrder', {'environment': 'PRE'})
        return jsonify({'result': 'success'})
    
    if __name__ == "__main__":
        # 將host設置為0.0.0.0,則外網用戶也可以訪問到這個服務
        app.run(host="0.0.0.0", port=80, debug=True)
    
    

    7.3 將上述flask封裝的接口打包成鏡像
    根據dockerfile生成鏡像

    FROM python:3.6
    WORKDIR /app
    EXPOSE 80
    COPY .	.
    RUN pip install -r requirements.txt 
    ENTRYPOINT ["python","robotTestApi.py"]
    
    

    7.4 將鏡像部署到kubernetes,對外提供服務
    供觸發測試執行的調用入口 ,這部分封裝的接口部署在本地的k8s集群下ordermiddle

    IT: http://ordermiddle.xxx.cn/test/it
    pre:http://ordermiddle.xxx.cn/test/pre

    7.5 被測項目的CICD集成接口自動化測試
    gitlab目前採取直接對CICD腳本加入測試步驟,在部署到容器30秒后(考慮到容器在K8S啟動時間)調用測試接口

    7.6 發送測試報告

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

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

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • 葡西法三國簽署能源互聯協議 法國將關閉所有煤電廠

    摘錄自2018年7月28日新華社報導

    葡萄牙、西班牙和法國27日在葡萄牙首都里斯本舉行的第二屆能源互聯峰會上正式簽署了三國能源互聯協議。

    根據協議,西葡兩國同歐洲的能源互聯水平到2020年達到10%,2030年達到15%。此外,歐盟委員會將投資5.7億歐元在西班牙以北的比斯開灣建造一個用於連接西班牙、葡萄牙和法國的電力互聯項目。

    葡萄牙總理科斯塔、西班牙首相桑切斯和法國總統馬克宏在會後舉行了聯合記者會。馬克宏表示,最晚到2022年,法國將關閉所有煤電廠。

    科斯塔說,葡萄牙計劃到2020年使清潔能源占比超過60%,葡萄牙在逐步減少煤電行業投入的同時尋求清潔能源出口。

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

    【其他文章推薦】

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

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • 季節變化間顯現 科學家找到人為暖化的「指紋」

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

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

    【其他文章推薦】

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

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

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

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?

  • 李澤楷收購菲斯科前夕遭遇萬向集團競購

    據悉,去年11月,停產一年的美國電動車製造商菲斯科(Fisker)申請破產保護。香港商人李澤楷組成的財團以2500萬美元購入Fisker欠美國政府的未償還貸款,並計畫購入該電動汽車廠商的餘下資產。

    按照原計劃,法院將於1月3日決定Fisker是否出售給李澤楷的關聯公司。不過,在交易得到美國法院首肯前夕,傳中國大陸萬向集團報價收購Fisker。

    據外媒報導,Fisker 12月31日提交給法院的檔顯示,Fisker債權人已經要求法院廢止Fisker同意將資產售予李澤楷的交易,並開展公開競拍,而萬向集團旗下萬向美國公司將參與競購。萬向集團已經同意初步開出2472.5萬美元的報價,並承擔Fisker部分債務。

    Fisker的產品為卡瑪插電式混合動力跑車,在美國市場售價高達10萬美元,但銷量一直不理想。據提交的檔顯示,萬向計畫最早在4月使Fisker恢復生產,並最終把製造業務從芬蘭遷回美國密西根州。

    去年1月,萬向集團曾以2.566億美元的價格收購了美國最大的新能源電池製造商A123系統公司。而菲斯科此前是A123系統公司的最大客戶。

    Fisker和A123兩家公司均獲得了美國能源部的綠色能源貸款,美國政府此前曾試圖阻撓把A123出售股權給萬向,因為美國監管方擔心敏感技術可能競爭對手手中。

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

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

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • 豐田氫燃料電池車FCV明年先在加州地區上路

    豐田氫燃料電池車FCV明年先在加州地區上路

    日本汽車龍頭豐田6日表示,將於2015年首先在美國市場推出具「零排放」功能的「氫燃料電池車」,此款車型名稱暫定為FCV,利用氫燃料電池做為動力來源,行駛時僅排放水蒸氣。該款車型的售價將控制在5~10萬美元之間。該款車型在日本市場的推出時間,料將與美國市場同步。豐田的競爭對手現代與本田也表示將於明年推出同類型的汽車。

    豐田銷售副資深副總卡特(Bob Carter)表示,FCV在功能上屬於一般車型,是一款零排放、電力驅動、中型規格、4門轎車的車款,將配合加州政府的充電站政策,於當地優先推出。

    豐田大幅改造氫燃料電池車的車型設計,使氫燃料電池在運作過程中,大幅降低對氧氣的需求。氫氣車在充滿電力後,可行駛300英里(約480公里)的車程。充電時間僅需費時3~5分鐘。

    豐田近來與加州大學合作,表示最初的1萬輛氫氣車,僅有舊金山與聖地牙哥一帶的68座充電站,能夠支援氫燃料電力。但為方便未來的充電需求,加州政府已通過2億美元經費,規劃在2015年、2016年、與2024年,分別新增20座、40座,與100個充電站。卡特指出,如果設置適當,只須利用加州目前1萬座加油站當中的15%,將其轉型成氫燃料充電站,就可充分提供電力需求。

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

    【其他文章推薦】

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

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

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

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?

  • python動態柱狀圖圖表可視化:歷年軟科中國大學排行

    python動態柱狀圖圖表可視化:歷年軟科中國大學排行

    本來想參照:https://mp.weixin.qq.com/s/e7Wd7aEatcLFGgJUDkg-EQ搞一個往年編程語言動態圖的,奈何找不到數據,有數據來源的歡迎在評論區留言。

    這裏找到了一個,是2020年6月的編程語言排行,供大家看一下:https://www.tiobe.com/tiobe-index/

     

    我們要實現的效果是:

    大學排名來源:http://www.zuihaodaxue.com/ARWU2003.html

    部分截圖:

    在http://www.zuihaodaxue.com/ARWU2003.html中的年份可以選擇,我們解析的頁面就有了:

    "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)

    初步獲取頁面的html信息的代碼:

    def get_one_page(year):
        try:
            headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
                }
            url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
            response=requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.content
        except RequestException:
            print('爬取失敗')

    我們在頁面上進行檢查:

    數據是存儲在表格中的,這樣我們就可以利用pandas獲取html中的數據,基本語法:

    tb = pd.read_html(url)[num]

    其中的num是標識網頁中的第幾個表格,這裏只有一個表格,所以標識為0。初步的解析代碼就有了:

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        return tb

    我們還要將爬取下來的數據存儲到csv文件中,基本代碼如下:

    def save_csv(tb):
        start_time=time.time()
        tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
        endtime = time.time()-start_time
        print('程序運行了%.2f秒' %endtime)

    最後是一個主函數,別忘了還有需要導入的包:

    import requests
    from requests.exceptions import RequestException
    import pandas as pd
    import time
    def main(year):
        for i in range(2003,year):
            html=get_one_page(i)
            tb=parse_on_page(html,i)
            #print(tb)
            save_csv(tb)
    if __name__ == "__main__":
        main(2004)

    運行之後,我們在同級目錄下就可以看到university.csv,部分內容如下:

    存在幾個問題:

    (1)缺少年份

    (2)最後一列沒有用

    (3)國家由於是圖片表示,沒有爬取下來

    (4)排名100以後的是一個區間

    我們接下來一一解決:

    (1)刪掉沒用的列

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2, 'score',4]
        tb.drop([2,4],axis=1,inplace=True)
        return tb

    新的結果:

    (2) 對100以後的進行唯一化,增加一列index作為排名標識

    tb['index_rank'] = tb.index
    tb['index_rank'] = tb['index_rank'].astype(int) + 1

    (3)新增加年份

    tb['year'] = i

    (4)新增加國家

    首先我們進行檢查:

    發現國家在td->a>img下的圖像路徑中有名字:UnitedStates。 我們可以取出src屬性,並用正則匹配名字即可。

    def get_country(html):
        soup = BeautifulSoup(html,'lxml')
        countries = soup.select('td > a > img')
        lst = []
        for i in countries:
            src = i['src']
            pattern = re.compile('flag.*\/(.*?).png')
            country = re.findall(pattern,src)[0]
            lst.append(country)
        return lst

    然後這麼使用:

    # read_html沒有爬取country,需定義函數單獨爬取
    tb['country'] = get_country(html)

    最終解析的整體函數如下:

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2, 'score',4]
        tb.drop([2,4],axis=1,inplace=True)
        tb['index_rank'] = tb.index
        tb['index_rank'] = tb['index_rank'].astype(int) + 1
        tb['year'] = i
        # read_html沒有爬取country,需定義函數單獨爬取
        tb['country'] = get_country(html)
        return tb

    運行之後:

    最後我們要提取屬於中國部分的相關信息:

    首先將年份改一下,獲取到2019年為止的信息:

    if __name__ == "__main__":
        main(2019)

    然後我們提取到中國高校的信息,直接看代碼理解:

    def analysis():
        df = pd.read_csv('university.csv')
        # 包含港澳台
        # df = df.query("(country == 'China')|(country == 'China-hk')|(country == 'China-tw')|(country == 'China-HongKong')|(country == 'China-Taiwan')|(country == 'Taiwan,China')|(country == 'HongKong,China')")[['university','year','index_rank']]
    
        # 只包括內地
        df = df.query("(country == 'China')")
        df['index_rank_score'] = df['index_rank']
        # 將index_rank列轉為整形
        df['index_rank'] = df['index_rank'].astype(int)
    
        # 美國
        # df = df.query("(country == 'UnitedStates')|(country == 'USA')")
    
        #求topn名
        def topn(df):
            top = df.sort_values(['year','index_rank'],ascending = True)
            return top[:20].reset_index()
        df = df.groupby(by =['year']).apply(topn)
    
        # 更改列順序
        df = df[['university','index_rank_score','index_rank','year']]
        # 重命名列
        df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
    
        # 輸出結果
        df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
        # index可以設置

    本來是想爬取從2003年到2019年的,運行時發現從2005年開始,頁面不一樣了,多了一列:

    方便起見,我們就只從2005年開始了,還需要修改一下代碼:

        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2,3, 'score',5]
        tb.drop([2,3,5],axis=1,inplace=True)

    最後是整體代碼:

    import requests
    from requests.exceptions import RequestException
    import pandas as pd
    import time
    from bs4 import BeautifulSoup
    import re
    def get_one_page(year):
        try:
            headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
                }
            url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
            response=requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.content
        except RequestException:
            print('爬取失敗')
    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2,3, 'score',5]
        tb.drop([2,3,5],axis=1,inplace=True)
        tb['index_rank'] = tb.index
        tb['index_rank'] = tb['index_rank'].astype(int) + 1
        tb['year'] = i
        # read_html沒有爬取country,需定義函數單獨爬取
        tb['country'] = get_country(html)
        return tb
    def save_csv(tb):
        start_time=time.time()
        tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
        endtime = time.time()-start_time
        print('程序運行了%.2f秒' %endtime)
    # 提取國家名稱
    def get_country(html):
        soup = BeautifulSoup(html,'lxml')
        countries = soup.select('td > a > img')
        lst = []
        for i in countries:
            src = i['src']
            pattern = re.compile('flag.*\/(.*?).png')
            country = re.findall(pattern,src)[0]
            lst.append(country)
        return lst
    def analysis():
        df = pd.read_csv('university.csv')
        # 包含港澳台
        # df = df.query("(country == 'China')|(country == 'China-hk')|(country == 'China-tw')|(country == 'China-HongKong')|(country == 'China-Taiwan')|(country == 'Taiwan,China')|(country == 'HongKong,China')")[['university','year','index_rank']]
    
        # 只包括內地
        df = df.query("(country == 'China')")
        df['index_rank_score'] = df['index_rank']
        # 將index_rank列轉為整形
        df['index_rank'] = df['index_rank'].astype(int)
    
        # 美國
        # df = df.query("(country == 'UnitedStates')|(country == 'USA')")
    
        #求topn名
        def topn(df):
            top = df.sort_values(['year','index_rank'],ascending = True)
            return top[:20].reset_index()
        df = df.groupby(by =['year']).apply(topn)
    
        # 更改列順序
        df = df[['university','index_rank_score','index_rank','year']]
        # 重命名列
        df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
    
        # 輸出結果
        df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
        # index可以設置
    def main(year):
        for i in range(2005,year):
            html=get_one_page(i)
            tb=parse_on_page(html,i)
            save_csv(tb)
            print(i,'年排名提取完成完成')
            analysis()
    if __name__ == "__main__":
        main(2019)

    運行之後會有一個university_ranking.csv,部分內容如下:

    接下來就是可視化過程了。

    1、 首先,到作者的github主頁:  
    https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js

    2、克隆倉庫文件,使用git

    # 克隆項目倉庫
    git clone https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js
    # 切換到項目根目錄
    cd Historical-ranking-data-visualization-based-on-d3.js
    # 安裝依賴
    npm install

    這裏如果git clone超時可參考:

    https://www.cnblogs.com/xiximayou/p/12305209.html

    需要注意的是,這裏的npm是我之前裝node.js裝了的,沒有的自己需要裝一下。

    在執行npm install時會報錯:

    先執行:

    npm init

    之後一直回車即可:

    再執行npm install

    任意瀏覽器打開bargraph.html網頁,點擊選擇文件,然後選擇前面輸出的university_ranking.csv文件,看下效果:

    只能製作動圖上傳了。

    可以看到,有了大致的可視化效果,但還存在很多瑕疵,比如:表順序顛倒了、字體不合適、配色太花哨等。可不可以修改呢?

    當然是可以的,只需要分別修改文件夾中這幾個文件的參數就可以了:

    • config.js 全局設置各項功能的開關,比如配色、字體、文字名稱、反轉圖表等等功能;

    • color.css 修改柱形圖的配色;

    • stylesheet.css 具體修改配色、字體、文字名稱等的css樣式;

    • visual.js 更進一步的修改,比如圖表的透明度等。

    知道在哪裡修改了以後,那麼,如何修改呢?很簡單,只需要簡單的幾步就可以實現:

    • 打開網頁,右鍵-檢查,箭頭指向想要修改的元素,然後在右側的css樣式表裡,雙擊各項參數修改參數,修改完元素就會發生變化,可以不斷微調,直至滿意為止。

        

    • 把參數複製到四個文件中對應的文件里並保存。

    • Git Bash運行npm run build,之後刷新網頁就可以看到優化后的效果。(我發現這一步其實不需要,而且會報錯,我直接修改config.js之後運行也成功了)

    這裏我主要修改的是config.js的以下項:

      // 倒序,使得最短的條位於最上方 
      reverse: true,
      // 附加信息內容。
      // left label
      itemLabel: "本年度第一大學",
      // right label
      typeLabel: "世界排名",
      //為了避免名稱重疊
      item_x: 500,
      // 時間標籤坐標。建議x:1000 y:-50開始嘗試,默認位置為x:null,y:null
      dateLabel_x: 1000,
      dateLabel_y: -50,

    最終效果:

    至此,就全部完成了。

    看起來簡單,還是得要自己動手才行。

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

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

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • 搶先日產 比亞迪全電動計程車隊進入倫敦

    中國汽車廠商比亞迪(BYD)今(11)日宣布,首支英國倫敦史上全電動計程車隊正式上路,在2018年前批量供應零排放出租車的競爭中,搶在了日產(Nissan)等國際競爭對手之前。不到2個月前,比亞迪還交付了倫敦史上首批全電動公共汽車。

    據《金融時報》報導,倫敦市長鮑里斯約翰遜(Boris Johnson)設定了全市計程車必須在2018年前實現零排放的目標,引發汽車廠商爭相開發新車。

    比亞迪趕在該期限之前率先打入了倫敦交通市場。比亞迪將推出20輛電動汽車組成的車隊,由出租車公司Thriev營運。

    另一方面,日本電動車廠商日產(Nissan)與英國經典黑出租車製造商倫敦出租車公司(London Taxi Company) ,也準備趕在2018年期限之前開發出全電動車型。

    著名的股神華倫•巴菲特(Warren Buffett)持有比亞迪9.9%股份。

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

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

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • 萬向集團出價1.49億美元 最終競得菲斯科

    萬向集團出價1.49億美元 最終競得菲斯科

    據外電報道,中國汽車零件製造商萬向集團擊敗李澤楷旗下的Hybrid Tech,在美國豪華混合動力汽車製造商Fisker的破產資產拍賣中勝出。萬向出價1.492億美元,大約是Fisker最初尋求的收購價的6倍。

    這次拍賣持續了三天,經歷了19輪投標。美國破產法官Kevin Gross按計劃將於2月18日批准此次出售。

    菲斯科在2009年獲得了美國能源部的5.29億美元綠色貸款。但能源部在2011年中期凍結支付,稱菲斯科在開發新車型上狀況頻出,一再拖延。

    2013年11月,菲斯科申請破產,並要求破產法官準許Hybrid Tech以2500萬美元的低價,向美國能源部購入Fisker原本總值1.6億多美元的貸款。Hybrid Tech從而成為Fisker的高級擔保貸款人,更表明有意進一步收購Fisker。

    但無擔保債權人反對這一報價,從而幫助中國最大的汽車零部件供應商於12月進入到交易環節中。

    在此筆交易達成后,萬向集團將努力重振菲斯科在中國汽車市場的發展,該集團也獲得了一個打進美國市場的入口點。據資料顯示,萬向為中國投資美國製造業、新能源和房地產的先行者,在過去20年,萬向於美國的投資遍布美國14個州,涉及汽車零件製造、不動產、新能源和私募基金等。

    2012年底時,萬向曾以近2.6億美元擊敗江森自控,成功拍得美國破產電池生產商A123鋰電池公司資產,這家公司正是Fisker的電池供應商。經營汽車零部件業務的萬向集團一直期望進軍整車制造領域。

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

    【其他文章推薦】

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

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

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

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?

  • 深入理解進程,線程,協程

    深入理解進程,線程,協程

    今日得到

    • 計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決

    • 併發:Do not communicate by sharing memory; instead, share memory by communicate. (不要以共享內存的方式來通信,相反,要通過通信來共享內存)

    1. 進程

    進程是系統進行資源分配和調度的一個獨立單位,程序段、數據段、PCB三部分組成了進程實體(進程映像),PCB是進程存在的唯一標準

    1.1 進程的組織方式:

    • 鏈接方式
      • 按照進程狀態將PCB分為多個隊列,就緒隊列,阻塞隊列等
      • 操作系統持有指向各個隊列的指針
    • 索引方式
      • 根據進程狀態的不同,建立幾張索引表
      • 操作系統持有指向各個索引表的指針

    1.2 進程的狀態

    • 創建態: 操作系統為進程分配資源,初始化PCB

    • 就緒態:運行資源等條件都滿足,存儲在就緒隊列中,等待CPU調度

    • 運行態:CPU正在執行進程

    • 阻塞態:等待某些條件滿足,等待消息回復,等待同步鎖,sleep等,阻塞隊列

    • 終止態 :回收進程擁有的資源,撤銷PCB

    1.3 進程的切換和調度

    進程在操作系統內核程序臨界區中不能進行調度與切換

    臨界資源:一個時間段內只允許一個進程使用資源,各進程需要互斥地訪問臨界資源

    臨界區:訪問臨界資源的代碼

    內核程序臨界區:訪問某種內核數據結構,如進程的就緒隊列(存儲各進程的PCB)

    進程調度的方式:

    • 非剝奪調度方式(非搶佔方式),只允許進程主動放棄處理機,在運行過程中即便有更緊迫的任務到達,當前進程依然會繼續使用處理機,直到該進程終止或者主動要求進入阻塞態
    • 剝奪調度方式(又稱搶佔方式)當一個進程正在處理機上執行時,如果有一個優先級更高的進程需要處理機,則立即開中斷暫停正在執行的進程,將處理機飯呢陪給優先級高的那個進程

    進程的切換與過程:進程的調度、切換是有代價的

    1. 對原來運行進程各種數據的保存
    2. 對新的進程各種數據恢復(程序計數器,程序狀態字,各種數據寄存器等處理機的現場)

    進程調度算法的相關參數:

    • CPU利用率:CPU忙碌時間/作業完成的總時間
    • 系統吞吐量:單位時間內完成作業的數量
    • 周轉時間:從作業被提交給系統開始,到作業完成為止的時間間隔 = 作業完成時間-作業提交時間
    • 帶權周轉時間:(由於周轉時間相同的情況下,可能實際作業的運行時間不一樣,這樣就會給用戶帶來不一樣的感覺) 作業周轉時間/作業實際運行時間, 帶權周轉時間>=1, 越小越好
    • 平均帶權周轉時間:各作業帶權周轉時間之和/作業數
    • 等待時間
    • 響應時間

    調度算法:

    算法思想,用於解決什麼問題?

    算法規則,用於作業(PCB作業)調度還是進程調度?

    搶佔式還是非搶佔式的?

    優缺點?是否會導致飢餓?

    以下調度算法是適用於當前交互式操作系統

    • 時間片輪轉(Round-Robin)
      • 算法思想:公平地、輪流地為各個進程服務,讓每個進程在一定時間間隔內可以得到相應
      • 算法規則:按照各進程到達就緒隊列的順序,輪流讓各個進程執行一個時間片(如100ms)。若進程未在一個時間片內執行完,則剝奪處理機,將進程重新放到就緒隊列隊尾重新排隊。
      • 用於作業/進程調度:用於進程的調度(只有作業放入內存建立相應的進程后,才會被分配處理機時間片)
      • 是否可搶佔?若進程未能在規定時間片內完成,將被強行剝奪處理機使用權,由時鐘裝置發出時鐘中斷信號來通知CPU時間片到達
      • 優缺點:適用於分時操作系統,由於高頻率的進程切換,因此有一定開銷;不區分任務的緊急程度
      • 是否會導致飢餓? 不會
    • 優先級調度算法
      • 算法思想:隨着計算機的發展,特別是實時操作系統的出現,越來越多的應用場景需要根據任務的進程成都決定處理順序
      • 算法規則:每個作業/進程有各自的優先級,調度時選擇優先級最高的作業/進程
      • 用於作業/進程調度:即可用於作業調度(處於外存後備隊列中的作業調度進內存),也可用於進程調度(選擇就緒隊列中的進程,為其分配處理機),甚至I/O調度
      • 是否可搶佔? 具有可搶佔版本,也有非搶佔式的
      • 優缺點:適用於實時操作系統,用優先級區分緊急程度,可靈活地調整對各種作業/及進程的偏好程度。缺點:若源源不斷地提供高優先級進程,則可能導致飢餓
      • 是否會導致飢餓: 會
    • 多級反饋隊列調度算法
      • 算法思想:綜合FCFS、SJF(SPF)、時間片輪轉、優先級調度

      • 算法規則:

        • 1.設置多級就緒隊列,各級別隊列優先級從高到底,時間片從小到大
        • 2.新進程到達時先進入第1級隊列,按照FCFS原則排隊等待被分配時間片,若用完時間片進程還未結束,則進程進入下一級隊列隊尾
        • 3.只有第k級別隊列為空時,才會為k+1級對頭的進程分配時間片
      • 用於作業/進程調度:用於進程調度

      • 是否可搶佔? 搶佔式算法。在k級隊列的進程運行過程中,若更上級別的隊列(1-k-1級)中進入一個新進程,則由於新進程處於優先級高的隊列中,因此新進程會搶佔處理機,原理運行的進程放回k級隊列隊尾。

      • 優缺點:對各類型進程相對公平(FCFS的有點);每個新到達的進程都可以很快就得到相應(RR優點);短進程只用較少的時間就可完成(SPF)的有點;不必實現估計進程的運行時間;可靈活地調整對各類進程的偏好程度,比如CPU密集型進程、I/O密集型進程(拓展:可以將因I/O而阻塞的進程重新放回原隊列,這樣I/O型進程就可以保持較高優先級)

      • 是否會導致飢餓: 會

    2. 線程

    引入線程之後,進程只作為除CPU之外的系統資源的分配單元(如:打印機,內存地址空間等都是分配給進程的)

    線程的是實現方式:

    • 用戶級線程(User-Level Thread),用戶級線程由應用程序通過線程庫是實現如python (import thread), 線程的管理工作由應用程序負責。
    • 內核級線程(kernel-Level Thread),內核級線程的管理工作由操作系統內核完成,線程調度,切換等工作都由內核負責,因此內核級線程的切換必然需要在核心態下才能完成

    進程和線程的關係:一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程并行執行不同的任務。CPU的最小調度單元是線程,所以單進程多線程是可以利用多核CPU的。

    2.1 線程模型:

    • 用戶級線程模型(一對多模型)

    多個用戶態的線程對應着一個內核線程,程序線程的創建、終止、切換或者同步等線程工作必須自身來完成。python就是這種。雖然可以實現異步,但是不能有效利用多核(GIL)

    • 內核級線程模型 (一對一)

    這種模型直接調用操作系統的內核線程,所有線程的創建、終止、切換、同步等操作,都由內核來完成。C++就是這種

    • 兩級線程模型(M:N)

    這種線程模型會先創建多個內核級線程,然後用自身的用戶級線程去對應創建的多個內核級線程,自身的用戶級線程需要本身程序去調度,內核級的線程交給操作系統內核去調度。GO語言就是這種。

    python中的多線程因為GIL的存在,並不能利用多核CPU優勢,但是在阻塞的系統調用中,如sock.connect(), sock.recv()等耗時的I/O操作,當前的線程會釋放GIL,讓出處理器。但是單個線程內,阻塞調用上還是阻塞的。除了GIL之外,所有的多線程還有通病,他們都是被OS調用的,調度策略是搶佔式的,以保證同等有限級的線程都有機執行,帶來的問題就是:並不知道下一刻執行那個線程,也不知道正在執行什麼代碼,會存在競態條件

    3. 協程

    協程通過在線程中實現調度,避免了陷入內核級別的上下文切換造成的性能損失,進而突破了線程在IO上的性能瓶頸。

    python的協程源於yield指令

    • yield item 用於產出一個值,反饋給next()的調用方法
    • 讓出處理機,暫停執行生成器,讓調用方繼續工作,直到需要使用另一個值時再調用next()

    協程式對線程的調度,yield類似惰性求職方式可以視為一種流程控制工具,實現協作式多任務,python3.5引入了async/await表達式,使得協程證實在語言層面得到支持和優化,大大簡化之前的yield寫法。線程正式在語言層面得到支持和優化。線程是內核進行搶佔式調度的,這樣就確保每個線程都有執行的機會。而coroutine運行在同一個線程中,有語言層面運行時中的EventLoop(事件循環)來進行調度。在python中協程的調度是非搶佔式的,也就是說一個協程必須主動讓出執行機會,其他協程才有機會運行。讓出執行的關鍵字 await, 如果一個協程阻塞了,持續不讓出CPU處理機,那麼整個線程就卡住了,沒有任何併發。

    PS: 作為服務端,event loop最核心的就是I/O多路復用技術,所有來自客戶端的請求都由I/O多路復用函數來處理;作為客戶端,event loop的核心在於Future對象延遲執行,並使用send函數激發協程,掛起,等待服務端處理完成返回后再調用Callback函數繼續執行。[python 協程與go協程的區別]

    3.1 Golang 協程

    Go 天生在語言層面支持,和python類似都是用關鍵字,而GO語言使用了go關鍵字,go協程之間的通信,採用了channel關鍵字。

    go實現了兩種併發形式:

    • 多線程共享內存:如Java 或者C++在多線程中共享數據的時候,通過鎖來訪問
    • Go語言特有的,也是Go語言推薦的 CSP(communicating sequential processes)併發模型。
    package main 
    
    import ("fmt")
    
    func main() {
        jobs := make(chan int)
        done := make(chan bool)  // end flag
        
        go func() {
            for {
                j, ok := <- jobs 
                fmt.Println("---->:", j, ok)
                if ok {
                    fmt.Println("received job")
                } else {
                    fmt.Println("end received jobs")
                    done <- true
                    return
                }
            }
        }()
        
        go func() {
            for j:= 1; j <= 3; j++ {
                jobs <-j
                fmt.Println("sent job", j)
            }
            close(jobs)
            fmt.Println("close(jobs)")
        }()
        
        fmt.Println("sent all jobs")
        <-done  // 阻塞 讓main等待協程完成
    }
    

    Go的CSP併發模型是通過goroutine 和 channel來實現的。

    • goroutine是go語言中併發的執行單位。
    • channel是Go語言中各個併發結構體之間的通信機制。
      • channel -< data 寫數據
      • <- channel 讀數據

    協程本質上來說是一種用戶態的線程,不需要系統來執行搶佔式調度,而是在語言測個面實現線程的調度。

    4. 併發

    併發:Do not communicate by sharing memory; instead, share memory by communicate.

    4.1 Actor模型

    Actor模型和CSP模型的區別:

    • CSP並不Focus發送消息的實體/Task, 而是關注發送消息時消息所使用的載體,即channel。
    • 在Actor的設計中,Actor與信箱是耦合的,而在CSP中channel是作為first-class獨立存在的
    • Actor中有明確的send/receive關係,而channel中並不區分這樣的關係,執行快可以任意選擇發送或者取消息

    好文推薦:Go/Python/Erlang編程語言對比分析及示例

    4.4 Go 協程調度器 GPM

    • G 指的是Goroutine,其本質上也是一種輕量級的線程
    • P proessor, 代表M所需要的上下文環境,也是處理用戶級代碼邏輯處理器。同一時間只有一個線程(M)可以擁有P, P中的數據都是鎖自由(lock free)的, 讀寫這些數據的效率會非常的高
    • M Machine,一個M直接關聯一個內核線程,可以運行go代碼 即goroutine, M運行go代碼需要一個P, 另外就是運行原生代碼,如 syscall。運行原生代碼不需要P。

    一個M會對應一個內核線程,一個M也會連接一個上下文P,一個上下文P相當於一個“處理器”,一個上下文連接一個或者多個Goroutine。P(Processor)的數量是在啟動時被設置為環境變量GOMAXPROCS的值,或者通過運行時調用函數runtime.GOMAXPROCS()進行設置

    erlang和golang都是採用CSP模型,python中協程是eventloop模型。但是erlang是基於進程的消息通信,go是基於goroutine和channel通信。

    python和golang都引入了消息調度系統模型,來避免鎖的影響和進程線程的開銷問題。

    計算機科學領域的任何問題都可以通過增加一個間接的中間層來解決 — G-P-M模型正是此理論踐行者,此理論也用到了python的asyncio對地獄回調的處理上(使用Task+Future避免回調嵌套),是不是巧合?
    其實異步≈可中斷的函數+事件循環+回調,go和python都把嵌套結構轉換成列表結構有點像算法中的遞歸轉迭代.

    調度器在計算機中是分配工作時所需要的資源,Linux的調度是CPU找到可運行的線程,Go的調度是為M線程找到P(內存,執行票據)和可運行的G(協程)

    Go協程是輕量級的,棧初始2KB(OS操作系統的線程一般都是固有的棧內存2M), 調度不涉及系統調用,用戶函數調用前會檢查棧空間是否足夠,不夠的話,會進行站擴容,棧大小限制可以達到1GB。

    Go的網絡操作是封裝了epoll, 為NonBlocking模式,切換協程不阻塞線程。

    Go語言相比起其他語言的優勢在於OS線程是由OS內核來調度的,goroutine則是由Go運行時(runtime)自己的調度器調度的,這個調度器使用一個稱為m:n調度的技術(復用/調度m個goroutine到n個OS線程)。 其一大特點是goroutine的調度是在用戶態下完成的, 不涉及內核態與用戶態之間的頻繁切換,包括內存的分配與釋放,都是在用戶態維護着一塊大的內存池, 不直接調用系統的malloc函數(除非內存池需要改變),成本比調度OS線程低很多。 另一方面充分利用了多核的硬件資源,近似的把若干goroutine均分在物理線程上, 再加上本身goroutine的超輕量,以上種種保證了go調度方面的性能。點我了解更多

    4.5 Go 調度器的實現 以及搶佔式調度

    legendtkl阿里雲技術專家

    Golang源碼探索(二) 協程的實現原理

    相關參考文獻:

    王道操作系統

    操作系統中調度算法(FCFS、RR、SPN、SRT、HRRN)

    Python協程與Go協程的區別二

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

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

    台北網頁設計公司這麼多該如何選擇?

    ※智慧手機時代的來臨,RWD網頁設計為架站首選

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準