現代轉攻新能源汽車 計畫2020年之前推26款新車

日前,據海外媒體報導,現代汽車集團將在2020年之前推出26款新能源汽車,其中包括旗下現代和起亞兩大品牌。現代汽車集團此舉意在搶佔新能源汽車市場的領先地位,爭取在2020年達到僅次於豐田的行業第二水準。

現代汽車集團計畫推出的26款新車型包括12款混動車型、6款插電式混動車型、2款純電動車型以及2款氫燃料電池車型等。其中,起亞將推出包括Niro混動版、凱尊(參配、圖片、詢價) 混動版、SoulEV在內的11款新車,而現代則會推出插電式混動版、純電動版IONIQ與豐田普銳斯一決高下。據現代汽車集團預估,到2020年現代汽車集團在新能源汽車市場的年銷量有望達到30萬台。

為了節省新能源汽車的開發成本,現代汽車集團相關負責人透露,旗下新能源車型將採用共用零部件策略。雖然每款車的動力系統在動力輸出上可能有所不同,但電動機直徑、核心部件等將會遵循統一化標準。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

【從今天開始好好學數據結構04】程序員你心中就沒點“樹”嗎?

目錄

前面我們講的都是線性表結構,棧、隊列等等。今天我們講一種非線性表結構,樹。樹這種數據結構比線性表的數據結構要複雜得多,內容也比較多,首先我們先從樹(Tree)開始講起。
@

樹(Tree)

樹型結構是一種非線性結構,它的數據元素之間呈現分支、分層的特點。

1.樹的定義

樹(Tree)是由n(n≥0)個結點構成的有限集合T,當n=0時T稱為空樹;否則,在任一非空樹T中:
(1)有且僅有一個特定的結點,它沒有前驅結點,稱其為根(Root)結點;
(2)剩下的結點可分為m(m≥0)個互不相交的子集T1,T2,…,Tm,其中每個子集本身又是一棵樹,並稱其為根的子樹(Subtree)。

注意:樹的定義具有遞歸性,即“樹中還有樹”。樹的遞歸定義揭示出了樹的固有特性

2.什麼是樹結構

什麼是“樹”?再好的定義,都沒有圖解來的直觀。所以我在圖中畫了幾棵“樹”。你來看看,這些“樹”都有什麼特徵?

你有沒有發現,“樹”這種數據結構真的很像我們現實生活中的“樹”

3.為什麼使用樹結構

在有序數組中,可以快速找到特定的值,但是想在有序數組中插入一個新的數據項,就必須首先找出新數據項插入的位置,然後將比新數據項大的數據項向後移動一位,來給新的數據項騰出空間,刪除同理,這樣移動很費時。顯而易見,如果要做很多的插入和刪除操作和刪除操作,就不該選用有序數組。另一方面,鏈表中可以快速添加和刪除某個數據項,但是在鏈表中查找數據項可不容易,必須從頭開始訪問鏈表的每一個數據項,直到找到該數據項為止,這個過程很慢。 樹這種數據結構,既能像鏈表那樣快速的插入和刪除,又能想有序數組那樣快速查找

4.樹的常用術語

結點——包含一個數據元素和若干指向其子樹的分支
度——結點擁有的子樹個數
樹的度——該樹中結點的最大度數
恭弘=叶 恭弘子——度為零的結點
分支結點(非終端結點)——度不為零的結點
孩子和雙親——結點的子樹的根稱為該結點的孩子,相應地,該結點稱為孩子的雙親
兄弟——同一個雙親的孩子
祖先和子孫——從根到該結點所經分支上的所有結點。相應地,以某一結點為根的子樹中的任一結點稱為該結點的子孫。
結點的層次——結點的層次從根開始定義,根結點的層次為1,其孩子結點的層次為2,……
堂兄弟——雙親在同一層的結點
樹的深度——樹中結點的最大層次
有序樹和無序樹——如果將樹中每個結點的各子樹看成是從左到右有次序的(即位置不能互換),則稱該樹為有序樹;否則稱為無序樹。
森林——m(m≥0)棵互不相交的樹的有限集合

到這裏,樹就講的差不多了,接下來講講二叉樹(Binary Tree)

二叉樹(Binary Tree)

樹結構多種多樣,不過我們最常用還是二叉樹,我們平時最常用的樹就是二叉樹。二叉樹的每個節點最多有兩個子節點,分別是左子節點和右子節點。二叉樹中,有兩種比較特殊的樹,分別是滿二叉樹和完全二叉樹。滿二叉樹又是完全二叉樹的一種特殊情況。

1.二叉樹的定義和特點

二叉樹的定義:
二叉樹(Binary Tree)是n(n≥0)個結點的有限集合BT,它或者是空集,或者由一個根結點和兩棵分別稱為左子樹和右子樹的互不相交的二叉樹組成 。
————————————
二叉樹的特點:
每個結點至多有二棵子樹(即不存在度大於2的結點);二叉樹的子樹有左、右之分,且其次序不能任意顛倒。

2.幾種特殊形式的二叉樹

1、滿二叉樹
定義:深度為k且有2k-1個結點的二叉樹,稱為滿二叉樹。
特點:每一層上的結點數都是最大結點數
2、完全二叉樹
定義:
深度為k,有n個結點的二叉樹當且僅當其每一個結點都與深度為k的滿二叉樹中編號從1至n的結點一一對應時,稱為完全二叉樹
特點:
特點一 : 恭弘=叶 恭弘子結點只可能在層次最大的兩層上出現;
特點二 : 對任一結點,若其右分支下子孫的最大層次為l,則其左分支下子孫的最大層次必為l 或l+1

建議看圖對應文字綜合理解

代碼創建二叉樹

首先,創建一個節點Node類

package demo5;
/*
 * 節(結)點類 
 */
public class Node {
    //節點的權
    int value;
    //左兒子(左節點)
    Node leftNode;
    //右兒子(右節點)
    Node rightNode;
    //構造函數,初始化的時候就給二叉樹賦上權值
    public Node(int value) {
        this.value=value;
    }
    
    //設置左兒子(左節點)
    public void setLeftNode(Node leftNode) {
        this.leftNode = leftNode;
    }
    //設置右兒子(右節點)
    public void setRightNode(Node rightNode) {
        this.rightNode = rightNode;
    }

接着創建一個二叉樹BinaryTree 類

package demo5;
/*
 * 二叉樹Class
 */
public class BinaryTree {
    //根節點root
    Node root;
    
    //設置根節點
    public void setRoot(Node root) {
        this.root = root;
    }
    
    //獲取根節點
    public Node getRoot() {
        return root;
    }
}

最後創建TestBinaryTree 類(該類主要是main方法用來測試)來創建一個二叉樹

package demo5;
public class TestBinaryTree {

    public static void main(String[] args) {
        //創建一顆樹
        BinaryTree binTree = new BinaryTree();
        //創建一個根節點
        Node root = new Node(1);
        //把根節點賦給樹
        binTree.setRoot(root);
        //創建一個左節點
        Node rootL = new Node(2);
        //把新創建的節點設置為根節點的子節點
        root.setLeftNode(rootL);
        //創建一個右節點
        Node rootR = new Node(3);
        //把新創建的節點設置為根節點的子節點
        root.setRightNode(rootR);
        //為第二層的左節點創建兩個子節點
        rootL.setLeftNode(new Node(4));
        rootL.setRightNode(new Node(5));
        //為第二層的右節點創建兩個子節點
        rootR.setLeftNode(new Node(6));
        rootR.setRightNode(new Node(7));
    }

}

下面將會講的遍歷、查找節點、刪除節點都將圍繞這三個類開展

不難看出創建好的二叉樹如下(畫的不好,還望各位見諒):

3.二叉樹的兩種存儲方式

二叉樹既可以用鏈式存儲,也可以用數組順序存儲。數組順序存儲的方式比較適合完全二叉樹,其他類型的二叉樹用數組存儲會比較浪費存儲空間,所以鏈式存儲更合適。

我們先來看比較簡單、直觀的鏈式存儲法

接着是基於數組的順序存儲法(該例子是一棵完全二叉樹)

上面例子是一棵完全二叉樹,所以僅僅“浪費”了一個下標為0的存儲位置。如果是非完全二叉樹,則會浪費比較多的數組存儲空間,如下。

還記得堆和堆排序嗎,堆其實就是一種完全二叉樹,最常用的存儲方式就是數組。

4.二叉樹的遍歷

前面我講了二叉樹的基本定義和存儲方法,現在我們來看二叉樹中非常重要的操作,二叉樹的遍歷。這也是非常常見的面試題。

經典遍歷的方法有三種,前序遍歷中序遍歷後序遍歷

前序遍歷是指,對於樹中的任意節點來說,先打印這個節點,然後再打印它的左子樹,最後打印它的右子樹。

中序遍歷是指,對於樹中的任意節點來說,先打印它的左子樹,然後再打印它本身,最後打印它的右子樹。

後序遍歷是指,對於樹中的任意節點來說,先打印它的左子樹,然後再打印它的右子樹,最後打印這個節點本身。

我想,睿智的你已經想到了二叉樹的前、中、後序遍歷就是一個遞歸的過程。比如,前序遍歷,其實就是先打印根節點,然後再遞歸地打印左子樹,最後遞歸地打印右子樹。

在之前創建好的二叉樹代碼之上,我們來使用這三種方法遍歷一下~

依舊是在Node節點類上添加方法:可以看出遍歷方法都是用的遞歸思想

package demo5;
/*
 * 節(結)點類 
 */
public class Node {
//===================================開始 遍歷========================================
    //前序遍歷
    public void frontShow() {
        //先遍歷當前節點的內容
        System.out.println(value);
        //左節點
        if(leftNode!=null) {
            leftNode.frontShow();
        }
        //右節點
        if(rightNode!=null) {
            rightNode.frontShow();
        }
    }

    //中序遍歷
    public void midShow() {
        //左子節點
        if(leftNode!=null) {
            leftNode.midShow();
        }
        //當前節點
        System.out.println(value);
        //右子節點
        if(rightNode!=null) {
            rightNode.midShow();
        }
    }

    //後序遍歷
    public void afterShow() {
        //左子節點
        if(leftNode!=null) {
            leftNode.afterShow();
        }
        //右子節點
        if(rightNode!=null) {
            rightNode.afterShow();
        }
        //當前節點
        System.out.println(value);
    }

}

然後依舊是在二叉樹BinaryTree 類上添加方法,並且添加的方法調用Node類中的遍歷方法

package demo5;
/*
 * 二叉樹Class
 */
public class BinaryTree {

    public void frontShow() {
        if(root!=null) {
            //調用節點類Node中的前序遍歷frontShow()方法
            root.frontShow();
        }
    }

    public void midShow() {
        if(root!=null) {
            //調用節點類Node中的中序遍歷midShow()方法
            root.midShow();
        }
    }

    public void afterShow() {
        if(root!=null) {
            //調用節點類Node中的後序遍歷afterShow()方法
            root.afterShow();
        }
    }

}

依舊是在TestBinaryTree類中測試

package demo5;

public class TestBinaryTree {

    public static void main(String[] args) {
        //前序遍歷樹
        binTree.frontShow();
        System.out.println("===============");
        //中序遍歷
        binTree.midShow();
        System.out.println("===============");
        //後序遍歷
        binTree.afterShow();
        System.out.println("===============");
        //前序查找
        Node result = binTree.frontSearch(5);
        System.out.println(result);
        
}

如果遞歸理解的不是很透,我可以分享一個學習的小方法:我建議各位可以這樣斷點調試,一步一步調,思維跟上,仔細推敲每一步的運行相信我,你會重新認識到遞歸!(像下面這樣貼個圖再一步一步斷點思維更加清晰)

貼一下我斷點對遞歸的分析,希望對你有一定的幫助~

二叉樹遍歷的遞歸實現思路自然、簡單,易於理解,但執行效率較低。為了提高程序的執行效率,可以顯式的設置棧,寫出相應的非遞歸遍歷算法。非遞歸的遍歷算法可以根據遞歸算法的執行過程寫出。至於代碼可以嘗試去寫一寫,這也是一種提升!具體的非遞歸算法主要流程圖貼在下面了:

二叉樹遍歷算法分析:

二叉樹遍歷算法中的基本操作是訪問根結點,不論按哪種次序遍歷,都要訪問所有的結點,對含n個結點的二叉樹,其時間複雜度均為O(n)。所需輔助空間為遍歷過程中所需的棧空間,最多等於二叉樹的深度k乘以每個結點所需空間數,最壞情況下樹的深度為結點的個數n,因此,其空間複雜度也為O(n)。

5.二叉樹中節點的查找與刪除

剛才講到二叉樹的三種金典遍歷放法,那麼節點的查找同樣是可以效仿的,分別叫做前序查找、中序查找以及後序查找,下面代碼只以前序查找為例,三者查找方法思路類似~

至於刪除節點,有三種情況:

1、如果刪除的是根節點,那麼二叉樹就完全被刪了
2、如果刪除的是雙親節點,那麼該雙親節點以及他下面的所有子節點所構成的子樹將被刪除
3、如果刪除的是恭弘=叶 恭弘子節點,那麼就直接刪除該恭弘=叶 恭弘子節點

那麼,我把完整的三個類給貼出來(包含創建、遍歷、查找、刪除)

依舊是Node節點類

package demo5;
/*
 * 節(結)點類 
 */
public class Node {
    //節點的權
    int value;
    //左兒子
    Node leftNode;
    //右兒子
    Node rightNode;
    //構造函數,初始化的時候就給二叉樹賦上權值
    public Node(int value) {
        this.value=value;
    }
    
    //設置左兒子
    public void setLeftNode(Node leftNode) {
        this.leftNode = leftNode;
    }
    //設置右兒子
    public void setRightNode(Node rightNode) {
        this.rightNode = rightNode;
    }
    
    //前序遍歷
    public void frontShow() {
        //先遍歷當前節點的內容
        System.out.println(value);
        //左節點
        if(leftNode!=null) {
            leftNode.frontShow();
        }
        //右節點
        if(rightNode!=null) {
            rightNode.frontShow();
        }
    }

    //中序遍歷
    public void midShow() {
        //左子節點
        if(leftNode!=null) {
            leftNode.midShow();
        }
        //當前節點
        System.out.println(value);
        //右子節點
        if(rightNode!=null) {
            rightNode.midShow();
        }
    }

    //後序遍歷
    public void afterShow() {
        //左子節點
        if(leftNode!=null) {
            leftNode.afterShow();
        }
        //右子節點
        if(rightNode!=null) {
            rightNode.afterShow();
        }
        //當前節點
        System.out.println(value);
    }

    //前序查找
    public Node frontSearch(int i) {
        Node target=null;
        //對比當前節點的值
        if(this.value==i) {
            return this;
        //當前節點的值不是要查找的節點
        }else {
            //查找左兒子
            if(leftNode!=null) {
                //有可能可以查到,也可以查不到,查不到的話,target還是一個null
                target = leftNode.frontSearch(i);
            }
            //如果不為空,說明在左兒子中已經找到
            if(target!=null) {
                return target;
            }
            //查找右兒子
            if(rightNode!=null) {
                target=rightNode.frontSearch(i);
            }
        }
        return target;
    }
    
    //刪除一個子樹
    public void delete(int i) {
        Node parent = this;
        //判斷左兒子
        if(parent.leftNode!=null&&parent.leftNode.value==i) {
            parent.leftNode=null;
            return;
        }
        //判斷右兒子
        if(parent.rightNode!=null&&parent.rightNode.value==i) {
            parent.rightNode=null;
            return;
        }
        
        //遞歸檢查並刪除左兒子
        parent=leftNode;
        if(parent!=null) {
            parent.delete(i);
        }
        
        //遞歸檢查並刪除右兒子
        parent=rightNode;
        if(parent!=null) {
            parent.delete(i);
        }
    }

}

依舊是BinaryTree 二叉樹類

package demo5;
/*
 * 二叉樹Class
 */
public class BinaryTree {
    //根節點root
    Node root;
    
    //設置根節點
    public void setRoot(Node root) {
        this.root = root;
    }
    
    //獲取根節點
    public Node getRoot() {
        return root;
    }

    public void frontShow() {
        if(root!=null) {
            //調用節點類Node中的前序遍歷frontShow()方法
            root.frontShow();
        }
    }

    public void midShow() {
        if(root!=null) {
            //調用節點類Node中的中序遍歷midShow()方法
            root.midShow();
        }
    }

    public void afterShow() {
        if(root!=null) {
            //調用節點類Node中的後序遍歷afterShow()方法
            root.afterShow();
        }
    }
    //查找節點i
    public Node frontSearch(int i) {
        return root.frontSearch(i);
    }
    //刪除節點i
    public void delete(int i) {
        if(root.value==i) {
            root=null;
        }else {
            root.delete(i);
        }
    }
    
}

依舊是TestBinaryTree測試類

package demo5;

public class TestBinaryTree {

    public static void main(String[] args) {
        //創建一顆樹
        BinaryTree binTree = new BinaryTree();
        //創建一個根節點
        Node root = new Node(1);
        //把根節點賦給樹
        binTree.setRoot(root);
        //創建一個左節點
        Node rootL = new Node(2);
        //把新創建的節點設置為根節點的子節點
        root.setLeftNode(rootL);
        //創建一個右節點
        Node rootR = new Node(3);
        //把新創建的節點設置為根節點的子節點
        root.setRightNode(rootR);
        //為第二層的左節點創建兩個子節點
        rootL.setLeftNode(new Node(4));
        rootL.setRightNode(new Node(5));
        //為第二層的右節點創建兩個子節點
        rootR.setLeftNode(new Node(6));
        rootR.setRightNode(new Node(7));
        //前序遍歷樹
        binTree.frontShow();
        System.out.println("===============");
        //中序遍歷
        binTree.midShow();
        System.out.println("===============");
        //後序遍歷
        binTree.afterShow();
        System.out.println("===============");
        //前序查找
        Node result = binTree.frontSearch(5);
        System.out.println(result);
        
        System.out.println("===============");
        //刪除一個子樹
        binTree.delete(4);
        binTree.frontShow();
        
    }

}

到這裏,總結一下,我們學了一種非線性表數據結構,樹。關於樹,有幾個比較常用的概念你需要掌握,那就是:根節點、恭弘=叶 恭弘子節點、父節點、子節點、兄弟節點,還有節點的高度、深度、層數,以及樹的高度等。我們平時最常用的樹就是二叉樹。二叉樹的每個節點最多有兩個子節點,分別是左子節點和右子節點。二叉樹中,有兩種比較特殊的樹,分別是滿二叉樹和完全二叉樹。滿二叉樹又是完全二叉樹的一種特殊情況。二叉樹既可以用鏈式存儲,也可以用數組順序存儲。數組順序存儲的方式比較適合完全二叉樹,其他類型的二叉樹用數組存儲會比較浪費存儲空間。除此之外,二叉樹里非常重要的操作就是前、中、後序遍歷操作,遍歷的時間複雜度是O(n),你需要理解並能用遞歸代碼來實現。

如果本文章對你有幫助,哪怕是一點點,請點個讚唄,謝謝~

歡迎各位關注我的公眾號,一起探討技術,嚮往技術,追求技術…說好了來了就是盆友喔…

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

印尼省長要整治世界最髒河流 目標可飲用

摘錄自2018年9月20日中央社雅加達報導

西大魯河(Citarum River)全長300公里,是西爪哇省最長河流,是逾3500萬民眾生活用水來源,也是印尼重要的灌溉河流。美國布萊克史密斯研究所(Blacksmith Institute)研究顯示,每天排入西大魯河的化學廢料多達280公噸,有毒化學物質已達驚人程度,河水的鉛含量比美國的安全飲用水標準超出至少1000倍,因此被稱為「全世界最髒的河流」。

西爪哇省新任省長利德宛(Ridwan Kamil)向印尼國家通訊社安塔拉(Antara)表示,他有多管齊下的計畫,可以實現總統佐科威日前訂下的目標,讓西大魯河的水質在2025年前達到飲用標準。

整體計畫先期將先由印尼國營的軍武公司賓達(PT Pindad)設計的疏浚機開路,清理河中數量龐大的垃圾。中程計畫則將引進較佳的系統,用來遏阻和處理大批垃圾被傾倒至西大魯河的問題。

利德宛指出,長期而言,西爪哇省政府希望把周遭工業區及工廠遷移至其他地方。同時也要關注位於雅加達近郊勿加西(Bekasi)的瑪琅河(Malang River)等水路。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

020.掌握Pod-Pod基礎使用

一 Pod定義詳解

1.1 完整Pod定義文件

  1 apiVersion: v1			#必選,版本號,例如v1,版本號必須可以用 kubectl api-versions 查詢到
  2 kind: Pod				#必選,Pod
  3 metadata:				#必選,元數據
  4   name: string			#必選,Pod名稱,需符合RFC 1035規範
  5   namespace: string			#必選,Pod所屬的命名空間,默認為"default"
  6   labels:				#自定義標籤
  7     - name: string			#自定義標籤名字
  8   annotations:			#自定義註釋列表
  9     - name: string
 10 spec:				#必選,Pod中容器的詳細定義
 11   containers:			#必選,Pod中容器列表
 12   - name: string			#必選,容器名稱,需符合RFC 1035規範
 13     image: string			#必選,容器的鏡像名稱
 14     imagePullPolicy: [ Always|Never|IfNotPresent ]	#獲取鏡像的策略,Alawys表示每次都嘗試下載鏡像,IfnotPresent表示優先使用本地鏡像,否則下載鏡像,Nerver表示僅使用本地鏡像
 15     command: [string]		#容器的啟動命令列表,如不指定,使用打包時使用的啟動命令
 16     args: [string]			#容器的啟動命令參數列表
 17     workingDir: string		#容器的工作目錄
 18     volumeMounts:			#掛載到容器內部的存儲卷配置
 19     - name: string			#引用pod定義的共享存儲卷的名稱,需用volumes[]部分定義的的卷名
 20       mountPath: string		#存儲卷在容器內mount的絕對路徑,應少於512字符
 21       readOnly: boolean		#是否為只讀模式,默認為讀寫模式
 22     ports:				#需要暴露的端口庫號列表
 23     - name: string			#端口的名稱
 24       containerPort: int		#容器需要監聽的端口號
 25       hostPort: int		        #容器所在主機需要監聽的端口號,默認與Container相同
 26       protocol: string		#端口協議,支持TCP和UDP,默認TCP
 27     env:				#容器運行前需設置的環境變量列表
 28     - name: string			#環境變量名稱
 29       value: string		        #環境變量的值
 30     resources:			#資源限制和請求的設置
 31       limits:			#資源限制的設置
 32         cpu: string		        #CPU的限制,單位為core數,將用於docker run --cpu-shares參數
 33         memory: string		#內存限制,單位可以為Mib/Gib,將用於docker run --memory參數
 34       requests:			#資源請求的設置
 35         cpu: string		        #CPU請求,容器啟動的初始可用數量
 36         memory: string		#內存請求,容器啟動的初始可用數量
 37     livenessProbe:			#對Pod內各容器健康檢查的設置,當探測無響應幾次后將自動重啟該容器,檢查方法有exec、httpGet和tcpSocket,對一個容器只需設置其中一種方法即可
 38       exec:			        #對Pod容器內檢查方式設置為exec方式
 39         command: [string]		#exec方式需要制定的命令或腳本
 40       httpGet:			#對Pod內個容器健康檢查方法設置為HttpGet,需要制定Path、port
 41         path: string
 42         port: number
 43         host: string
 44         scheme: string
 45         HttpHeaders:
 46         - name: string
 47           value: string
 48       tcpSocket:			#對Pod內個容器健康檢查方式設置為tcpSocket方式
 49          port: number
 50        initialDelaySeconds: 0	#容器啟動完成后首次探測的時間,單位為秒
 51        timeoutSeconds: 0		#對容器健康檢查探測等待響應的超時時間,單位秒,默認1秒
 52        periodSeconds: 0		#對容器監控檢查的定期探測時間設置,單位秒,默認10秒一次
 53        successThreshold: 0
 54        failureThreshold: 0
 55        securityContext:
 56          privileged: false
 57     restartPolicy: [Always | Never | OnFailure]	#Pod的重啟策略,Always表示一旦不管以何種方式終止運行,kubelet都將重啟,OnFailure表示只有Pod以非0退出碼退出才重啟,Nerver表示不再重啟該Pod
 58     nodeSelector: obeject		#設置NodeSelector表示將該Pod調度到包含這個label的node上,以key:value的格式指定
 59     imagePullSecrets:		#Pull鏡像時使用的secret名稱,以key:secretkey格式指定
 60     - name: string
 61     hostNetwork: false		#是否使用主機網絡模式,默認為false,如果設置為true,表示使用宿主機網絡
 62     volumes:			#在該pod上定義共享存儲卷列表
 63     - name: string			#共享存儲卷名稱 (volumes類型有很多種)
 64       emptyDir: {}			#類型為emtyDir的存儲卷,與Pod同生命周期的一個臨時目錄。為空值
 65       hostPath: string		#類型為hostPath的存儲卷,表示掛載Pod所在宿主機的目錄
 66         path: string		#Pod所在宿主機的目錄,將被用於同期中mount的目錄
 67       secret:			#類型為secret的存儲卷,掛載集群與定義的secre對象到容器內部
 68         scretname: string
 69         items:
 70         - key: string
 71           path: string
 72       configMap:			#類型為configMap的存儲卷,掛載預定義的configMap對象到容器內部
 73         name: string
 74         items:
 75         - key: string
 76           path: string

二 Pod的基本用法

2.1 創建Pod


Pod可以由1個或多個容器組合而成,通常對於緊耦合的兩個應用,應該組合成一個整體對外提供服務,則應該將這兩個打包為一個pod。

屬於一個Pod的多個容器應用之間相互訪問只需要通過localhost即可通信,這一組容器被綁定在一個環境中。

  1 [root@k8smaster01 study]# vi frontend-localredis-pod.yaml
  2 apiVersion: v1
  3 kind: Pod
  4 metadata:
  5   name: redis-php
  6   label:
  7     name: redis-php
  8 spec:
  9   containers:
 10   - name: frontend
 11     image: kubeguide/guestbook-php-frontend:localredis
 12     ports:
 13     - containersPort: 80
 14   - name: redis-php
 15     image: kubeguide/redis-master
 16     ports:
 17     - containersPort: 6379
 18 
 19 [root@k8smaster01 study]# kubectl create -f frontend-localredis-pod.yaml
 20 


2.2 查看Pod

  1 [root@k8smaster01 study]# kubectl get pods	                #READY為2/2,表示此Pod中運行了yaml定義的兩個容器
  2 NAME        READY   STATUS    RESTARTS   AGE
  3 redis-php   2/2     Running   0          7m45s
  4 [root@k8smaster01 study]# kubectl describe pod redis-php	#查看詳細信息
  5 


三 靜態Pod

3.1 靜態Pod概述


靜態pod是由kubelet進行管理的僅存在於特定Node的Pod上,他們不能通過API Server進行管理,無法與ReplicationController、Deployment或者DaemonSet進行關聯,並且kubelet無法對他們進行健康檢查。靜態Pod總是由kubelet進行創建,並且總是在kubelet所在的Node上運行。

創建靜態Pod有兩種方式:配置文件或者HTTP方式。

3.2 配置文件方式創建

  1 [root@k8snode01 ~]# mkdir -p /etc/kubelet.d
  2 [root@k8snode01 ~]# vi /etc/kubelet.d/static-web.yaml
  3 apiVersion: v1
  4 kind: Pod
  5 metadata:
  6   name: static-web
  7   label:
  8     name: static-web
  9 spec:
 10   containers:
 11   - name: static-web
 12     image: nginx
 13     ports:
 14     - name: web
 15       containersPort: 80
 16 
 17 [root@k8snode01 ~]# vi /etc/systemd/system/kubelet.service
 18 ……
 19   --config=/etc/kubelet.d/ \·				#加入此參數
 20 ……
 21 [root@k8snode01 ~]# systemctl daemon-reload
 22 [root@k8snode01 ~]# systemctl restart kubelet.service	#重啟kubelet
 23 [root@k8snode01 ~]# docker ps				#查看創建的pod



提示:由於靜態pod不能通過API Server進行管理,因此在Master節點執行刪除操作後會變為Pending狀態,且無法刪除。刪除該pod只能在其運行的node上,將定義POD的yaml刪除。

3.3 HTTP方式


通過設置kubelet的啟動參數–mainfest-url,會定期從該URL下載Pod的定義文件,並以.yaml或.json文件的格式進行解析,從而創建Pod。

四 Pod容器共享Volume

4.1 共享Volume


在同一個Pod中的多個容器能夠共享Pod級別的存儲就Volume。Volume可以被定義為各種類型,多個容器各自進行掛載操作,將一個Volume掛載為容器內部需要的目錄。


示例1:

Pod級別設置Volume “app-logs”,同時Pod包含兩個容器,Tomcat向該Volume寫日誌,busybox讀取日誌文件。

  1 [root@k8smaster01 study]# vi pod-volume-applogs.yaml
  2 apiVersion: v1
  3 kind: Pod
  4 metadata:
  5   name: volume-pod
  6 spec:
  7   containers:
  8   - name: tomcat
  9     image: tomcat
 10     ports:
 11     - containerPort: 8080
 12     volumeMounts:
 13     - name: app-logs
 14       mountPath: /usr/local/tomcat/logs
 15   - name: logreader
 16     image: busybox
 17     command: ["sh","-c","tail -f /logs/catalina*.log"]
 18     volumeMounts:
 19     - name: app-logs
 20       mountPath: /logs
 21   volumes:
 22   - name: app-logs
 23     emptyDir: {}

解釋:

Volume名:app-logs;

emptyDir:為Pod分配到Node的時候創建。無需指定宿主機的目錄文件,為Kubernetes自動分配的目錄。

  1 [root@k8smaster01 study]# kubectl create -f pod-volume-applogs.yaml	#創建
  2 [root@k8smaster01 study]# kubectl get pods				#查看
  3 [root@k8smaster01 study]# kubectl logs volume-pod -c busybox	#讀取log




  1 [root@k8smaster01 study]# kubectl exec -it volume-pod -c tomcat -- ls /usr/local/tomcat/logs
  2 catalina.2019-06-29.log      localhost_access_log.2019-06-29.txt
  3 host-manager.2019-06-29.log  manager.2019-06-29.log
  4 localhost.2019-06-29.log
  5 [root@k8smaster01 study]# kubectl exec -it volume-pod -c tomcat -- tail /usr/local/tomcat/logs/catalina.2019-06-29.log



提示:通過tomcat容器可查看日誌,對比busybox通過共享Volume查看的日誌是否一致。

五 Pod配置管理

5.1 Pod配置概述


應用部署的一個最佳實踐是將應用所需的配置信息與程序進行分離,使程序更加靈活。將相應的應用打包為鏡像,可以通過環境變量或者外掛volume的方式在創建容器的時候進行配置注入,從而實現更好的復用。

Kubernetes提供一種統一的應用配置管理方案:ConfigMap。

5.2 ConfigMap概述


ConfigMap供容器使用的主要場景:

  • 生成容器內部的環境變量;
  • 設置容器的啟動命令的參數(需設置為環境變量);
  • 以volume的形式掛載為容器內部的文件或者目錄。


ConfigMap以一個或多個key:value的形式定義。value可以是string也可以是一個文件內容,可以通過yaml配置文件或者通過kubectl create configmap 的方式創建configMap。

5.3 創建ConfigMap資源對象——yaml方式

  1 [root@k8smaster01 study]# vi cm-appvars.yaml
  2 apiVersion: v1
  3 kind: ConfigMap
  4 metadata:
  5   name: cm-appvars
  6 data:
  7   apploglevel: info
  8   appdatadir: /var/data
  9 
 10 [root@k8smaster01 study]# kubectl create -f cm-appvars.yaml
 11 configmap/cm-appvars created
 12 [root@k8smaster01 study]# kubectl get configmaps
 13 NAME         DATA   AGE
 14 cm-appvars   2      8s
 15 [root@k8smaster01 study]# kubectl describe configmaps cm-appvars



  1 [root@k8smaster01 study]# kubectl get configmaps cm-appvars -o yaml


5.4 創建ConfigMap資源對象——命令行方式


語法1

  1 # kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source



解釋:通過–from-file參數從文件中創建,可以指定key名稱,也可以制定多個key。

語法2

  1 # kubectl create configmap NAME --from-file=config-files-dir



解釋:通過–from-file參數從目錄中創建,該目錄下的每個配置文件名都被設置為key,文件的內容被設置為value。

語法3

  1 # kubectl create configmap NAME --from-literal=key1=value1 --from-literal=key2=value2



解釋:通過–from-literal參數從文本中創建,直接將指定的key#=value#創建為ConfigMap的內容。

5.5 Pod使用ConfigMap


容器應用使用ConfigMap有兩種方式:

  • 通過環境變量獲取ConfigMap中的內容;
  • 通過Volume掛載的方式將ConfigMap中的內容掛載為容器內容的文件或目錄。

  1 [root@k8smaster01 study]# vi cm-test-pod.yaml
  2 apiVersion: v1
  3 kind: Pod
  4 metadata:
  5   name: cm-test-pod
  6 spec:
  7   containers:
  8   - name: cm-test
  9     image: busybox
 10     command: ["/bin/sh","-c","env|grep APP"]	#容器里執行查看環境變量的命令
 11     env:
 12     - name: APPLOGLEVEL				#定義容器環境變量名稱
 13       valueFrom:
 14         configMapKeyRef:			#環境變量的值來自ConfigMap
 15           name: cm-appvars			#指定來自cm-appvars的ConfigMap
 16           key: apploglevel			#key為apploglevel
 17     - name: APPDATADIR
 18       valueFrom:
 19         configMapKeyRef:
 20           name: cm-appvars
 21           key: appdatadir
 22 
 23 [root@k8smaster01 study]# kubectl create -f cm-test-pod.yaml
 24 [root@k8smaster01 study]# kubectl get pods
 25 NAME          READY   STATUS      RESTARTS   AGE
 26 cm-test-pod   0/1     Completed   2          24s



【掛載形式-待補充】

5.6 ConfigMap限制


  • Configmap必須在pod創建之間創建;
  • ConfigMap受到namespace的限制,只有同一個命名空間下才能引用;
  • ConfigMap暫時無法配置配額;
  • 靜態的pod無法使用ConfigMap;
  • 在使用volumeMount掛載的時候,configMap基於items創建的文件會整體的將掛載數據卷的容器的目錄下的文件全部覆蓋。

六 Pod獲取自身信息

6.1 Downward API


pod擁有唯一的名字、IP地址,並且處於某個Namespace中。pod的容器內獲取pod的信息科通過Downward API實現。具體有以下兩種方式:

  • 環境變量:用於單個變量,可以將pod信息和container信息注入容器內部;
  • volume掛載:將數組類信息生成為文件,掛載至容器內部。


舉例1:通過Downward API將Pod的IP、名稱和所在的Namespace注入容器的環境變量。

  1 [root@k8smaster01 study]# vi dapi-test-pod.yaml
  2 apiVersion: v1
  3 kind: Pod
  4 metadata:
  5   name: dapi-test-pod
  6 spec:
  7   containers:
  8     - name: test-container
  9       image: busybox
 10       command: [ "/bin/sh", "-c", "env" ]
 11       env:
 12         - name: MY_POD_NAME
 13           valueFrom:
 14             fieldRef:
 15               fieldPath: metadata.name
 16         - name: MY_POD_NAMESPACE
 17           valueFrom:
 18             fieldRef:
 19               fieldPath: metadata.namespace
 20         - name: MY_POD_IP
 21           valueFrom:
 22             fieldRef:
 23               fieldPath: status.podIP
 24   restartPolicy: Never



提示:Downward API提供如下變量:

metadata.name:Pod的名稱,當Pod通過RC生成時,其名稱是RC隨機產生的唯一名稱;

status.podIP:Pod的IP地址,POd的IP屬於狀態數據,而非元數據;

metadata.namespace:Pod所在的namespace。

  1 [root@k8smaster01 study]# kubectl create -f dapi-test-pod.yaml
  2 [root@k8smaster01 study]# kubectl logs dapi-test-pod | grep MY_POD
  3 MY_POD_NAMESPACE=default
  4 MY_POD_IP=172.30.240.4
  5 MY_POD_NAME=dapi-test-pod
  6 



舉例2:通過Downward API將Container的自願請求和限制信息注入容器的環境變量。

  1 [root@k8smaster01 study]# vi dapi-test-pod-container-vars.yaml
  2 apiVersion: v1
  3 kind: Pod
  4 metadata:
  5   name: dapi-test-pod-container-vars
  6 spec:
  7   containers:
  8     - name: test-container
  9       image: busybox
 10       imagePullPolicy: Never
 11       command: [ "/bin/sh", "-c" ]
 12       args:
 13       - while true; do
 14           echo -en '\n';
 15           printenv MY_CPU_REQUEST MY_CPU_LIMIT;
 16           printenv MY_MEM_REQUEST MY_MEM_LIMIT;
 17           sleep 3600;
 18         done;
 19       resources:
 20         requests:
 21           memory: "32Mi"
 22           cpu: "125m"
 23         limits:
 24           memory: "64Mi"
 25           cpu: "250m"
 26       env:
 27         - name: MY_CPU_REQUEST
 28           valueFrom:
 29             resourceFieldRef:
 30               containerName: test-container
 31               resource: requests.cpu
 32         - name: MY_CPU_LIMIT
 33           valueFrom:
 34             resourceFieldRef:
 35               containerName: test-container
 36               resource: limits.cpu
 37         - name: MY_MEM_REQUEST
 38           valueFrom:
 39             resourceFieldRef:
 40               containerName: test-container
 41               resource: requests.memory
 42         - name: MY_MEM_LIMIT
 43           valueFrom:
 44             resourceFieldRef:
 45               containerName: test-container
 46               resource: limits.memory
 47   restartPolicy: Never



提示:Downward API提供如下變量:

requests.cpu:容器的CPU請求值;

limits.cpu:容器的CPU限制值;

requests.memory:容器的內存請求值;

limits.memory:容器的內存限制值。

  1 [root@k8smaster01 study]# kubectl create -f dapi-test-pod-container-vars.yaml
  2 [root@k8smaster01 study]# kubectl logs dapi-test-pod-container-vars
  3 1
  4 1
  5 33554432
  6 67108864



舉例3:通過Downward API將Pod的Label、Annotation列表通過Volume掛載為容器內的一個文件。

  1 [root@k8smaster01 study]# vi dapi-test-pod-volume.yaml
  2 apiVersion: v1
  3 kind: Pod
  4 metadata:
  5   name: dapi-test-pod-volume
  6   labels:
  7     zone: us-est-coast
  8     cluster: test-cluster1
  9     rack: rack-22
 10   annotations:
 11     build: two
 12     builder: john-doe
 13 spec:
 14   containers:
 15     - name: test-container
 16       image: busybox
 17       imagePullPolicy: Never
 18       command: [ "/bin/sh", "-c" ]
 19       args:
 20       - while true; do
 21           if [[ -e /etc/labels ]]; then
 22             echo -en '\n\n'; cat /etc/labels; fi;
 23           if [[ -e /etc/annotations ]]; then
 24             echo -en '\n\n'; cat /etc/annotations; fi;
 25           sleep 3600;
 26         done;
 27       volumeMounts:
 28         - name: podinfo
 29           mountPath: /etc
 30           readOnly: false
 31   volumes:
 32     - name: podinfo
 33       downwardAPI:
 34         items:
 35           - path: "labels"
 36             fieldRef:
 37               fieldPath: metadata.labels
 38           - path: "annotations"
 39             fieldRef:
 40               fieldPath: metadata.annotations



注意:Volume中的ddownwardAPI的items語法,將會以path的名稱生成文件。如上所示,會在容器內生產/etc/labels和/etc/annotations兩個文件,分別包含metadata.labels和metadata.annotations的全部Label。

  1 [root@k8smaster01 study]# kubectl create -f dapi-test-pod-volume.yaml
  2 [root@k8smaster01 study]# kubectl logs dapi-test-pod-volume
  3 



提示:DownwardAPI意義:

在某些集群中,集群中的每個節點需要將自身的標識(ID)及進程綁定的IP地址等信息事先寫入配置文件中,進程啟動時讀取此類信息,然後發布到某個類似註冊服務中心。此時可通過DowanwardAPI,將一個預啟動腳本或Init Container,通過環境變量或文件方式獲取Pod自身的信息,然後寫入主程序配置文件中,最後啟動主程序。本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

吸髒空氣容易失智 空污物濃度高 50歲以上患病風險增四成

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

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

統達能源宣布進軍中國大陸電動車市場

台灣統振集團旗下統達能源宣布,將聯合易能電網科技以及中國機車公司奔馬實業,共同進軍中國大陸電動車市場,以電動機車用鋰電池交換系統搶攻中國商機,最快將在2016年下半年於廣東、福建地區成立營運示範據點。

統達能源過去著重歐洲電動自行車店員市場開發,在歐洲已有10%市占率,本次為首度跨入電動機車電源的供應鏈。總經理楊模樺表示,合作夥伴易能電網科技整合了桶達的動力電池系統與台灣IBM的技術,打造「MIT(台灣製造)」的智能化電池交換服務系統,並已在台灣搭配電動機車實際上路。

奔馬實業去年在中國大陸共生產了20萬輛機車,帶來10億元人民幣的營收。本次與統達能源的合作,聚焦在電動機車與電池交換站營運事業。奔馬實業董事長湛玉娟認為,車店分離電池月租致的商業模式能透過電池交換服務系統的管理與遠端監控來提高電池之可靠性、安全性、壽命,降低營運商維護成本,並與物聯網概念結合。她相信,合作夥伴易能的電池交換系統將有效改善中國大陸電動機車的能源供給問題,也能改善電池環保管理問題。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

django學習與實踐

Django簡介

​ Django是一個由Python寫成的開放源代碼的Web應用框架,它最初是被用來開發管理勞倫斯出版集團旗下的一些以新聞內容為主的網站,即CMS(內容管理系統)軟件。 並於2005年7月在 BSD 許可證下發布。這套框架是以比利時的吉普賽爵士吉他手 Django Reinhardt 來命名的。由於 Django 的是在一個快節奏的新聞編輯室環境下開發的,它的目的是使常見的 Web 開發任務,快速和容易。

Django官網:https://www.djangoproject.com/

Django中文網:https://www.django.cn

Django的框架模式

  • Django採用了MTV設計模式

    M Models 模型
    T Templates 模板
    V Views 視圖

Django是一個Web應用框架,他是如何處理請求和響應的

URL ( urls.py )請求調度,當有緩存頁面的時候直接返回內容。
視圖函數( view.py )執行所請求的操作,通常包括讀寫數據庫。
模型( models.py )定義了 Python 中的數據並與之交互。通常包含在一個關係數據庫( MySQL、PostgreSQL SQLite 等),其他數據存儲是可能的( XML、文本文件、LDAP、等)。
請求執行任務后,視圖返回一個 HTTP 響應對象(通常是經過數據處理的一個模板)。可選的:視圖可以保存一個版本的 HTTP 響應對象,返回攜帶一個時間戳,來告訴瀏覽器這個視圖的更新時間。
模板通常返回 HTML 頁面。Django 模板語言提供了 HTML 的語法及邏輯。

安裝

第一行和第三行都可以隨便使用

網絡不好用第三行

pip install Django==2.1
#用國內的鏡像網站,如下
pip install Django==2.1 -i https://pypi.douban.com/simple

導入Django模塊

import django
print(django.get_version())
#結果:
2.1

基本配置

常用命令

查看django版本
python -m django --version
#結果
2.1
創建項目命令,項目名稱是mysite
django-admin startproject mysite
創建應用程序命令,確保在manage.py文件時在同一個目錄
#如果我們在項目外面,先要進入項目里
cd mysite
#windows使用dir查看當前在哪裡,如果有manage.py就代表我們可以正確使用下面的命令
#創建應用程序
python manage.py startapp app01

啟動django

python manage.py runserver
#默認端口是8000
#使用上面的命令就可以了,下面不經常用
#改端口
python manage.py runserver 8080
#改訪問地址和端口
python manage.py runserver 0.0.0.0:8080

生成模型變化遷移文件

python manage.py makemigrations

運行模型遷移文件遷移到數據庫中

python manage.py migrate

創建管理用戶

python manage.py createsuperuser
user:輸入:admin
email:不寫也行
password:輸入:admin123
驗證password:輸入:admin123
 讓你確認:輸入:y
    

注:自動重新加載 runserver,根據需要開發服務器自動重新加載Python代碼為每個請求。您不需要重新啟動服務器代碼更改生效。然而,像添加文件某些操作不觸發重新啟動,所以你必須重新啟動在這些情況下的服務器。

基本目錄結構及作用:
mysite/ # 項目的容器,名字隨便起
manage.py # 命令行實用工具,以各種方式與該Django項目進行交互
mysite/ # 實際的Python項目
init.py # 空文件,導入不出錯
settings.py # 這個Django項目配置
urls.py # 這個Django項目的URL聲明; 一個Django驅動網站的“目錄”
wsgi.py # 一個入口點為WSGI兼容的Web服務器,以滿足您的項目

Django自帶數據庫,我們也可以選擇不更改,項目開發中一般會更改使用的數據庫,更改數據庫配置在settings.py文件里

由於Django內部連接MySQL時使用的是MySQLdb模塊

目前可以使用mysql來代替pymysql了

我們需要去下載mysql
pip install mysql

在settings中修改DATABASES

DATABASES = {
    'default'{
        'ENGINE':'django.db.backends.mysql',
        'NAME':'你的數據庫名稱',
        'USER':'你的用戶名',
        'PASSWORD':'你的密碼',
        'HOST':'127.0.0.1',
        'PORT':'3306',
    }           
}

模板

也在settings里修改,主要放html文件

TEMPLATE_DIRS = (
os.path.join(BASE_DIR,'templates'),
)

靜態文件

也在settings里修改,放css,js等文件

STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)

路由系統

路由系統就像我們我們的書本的目錄,書本的目錄會告訴你那一頁是什麼,你翻到那一頁就能看到相關的文字,路由系統就是,你對這個路由系統里的一個url地址發起了請求,路由系統會到對應的views函數去進行相關的處理,即這個url要用某個指定的views函數去處理。

來看下示例,django是怎麼規定構造路由的

from app01 import views
urlpatterns = [
    path(r'^login$',views.LoginView),
    path(r'^register$',views.RegisterView),
]
from app1 import views
urlpatterns = [
url(r'^manage1/(\d)', views.manage1),
url(r'^manage2/(?P\w)/(?P\d)', views.manage2),
url(r'^manage3/(?P\w)', views.manage3,{'id':333}),]

注意:

url多傳一個參數,那views對應的函數就要多接收一個參數

要不然會報錯的

二級路由

如果映射url太多了,全寫在一個urls.py文件里顯得繁瑣,所以出現了二級路由

就是項目的urls.py文件負責接收客戶發過來請求它判斷你傳來的東西有沒有它下面應用里的urls.py文件里有沒有,如果有就告訴應用的的urls來接收,讓它去處理,沒有就給你報錯

一級路由寫法

項目的urls.py文件里

from django.urls import path, include
urlpatterns = [
    path(r'app01/',include('app1.urls'))
]

Django是如何處理一個請求的

當用戶請求從您的 Django 的網站頁面,這是該系統遵循以確定哪些 Python 代碼執行的算法:

Django 請求是 URL 配置模塊配置。通常通過值 ROOT_URLCONF 設置,但如果傳入 HttpRequest 對象具有 urlconf 屬性(由中間件設置),它的值將代替的可以使用 ROOT_URLCONF 的設置。
Django 的負載是 Python 模塊並尋找變量 urlpatterns。這是一個 django.conf.urls.url() 實例。
Django 的貫穿每個 URL 模式,從而,在所請求的 URL 匹配的第一個停止。
一旦某個正則表達式相匹配,就運行相對應的視圖函數(或基於類的視圖)。該視圖被傳遞以下參數:
HttpRequest 對象。
如果匹配的正則表達式沒有返回命名組,然後從正則表達式比賽是作為位置參數。
關鍵詞參數是由由正則表達式匹配的任何命名組,由指定的可選參數的任何覆蓋的 kwargs參數 django.conf.urls.url()。
如果沒有正則表達式匹配,或者如果一個異常在這個過程中的任何一點時提出,Django的調用適當的錯誤處理視圖。

官方示例

from django.conf.urls import url

from . import views

urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),]

注意事項:

要捕獲從URL中的值,用 括號括起來,會當參數傳入views視圖

沒有必要添加一個斜體,因為每個URL都有。例如,它^articles不是^/articles.

在‘r’前面的每一個正則表達式是可選的,建議,它告訴python字符串是原始的,沒有字符要轉義

舉例請求:

請求/articles/2005/03/將匹配列表中的第三項,Django將調用該函數。

views.month_archive(request,‘2005’,‘03’)

/articles/2005/3/ 不會匹配任何 URL 模式,因為在列表中的第三項中需要兩位数字的月份。

/articles/2003/ 將匹配的列表,而不是第二個第一圖案,因為該圖案,以便測試,第一個是在第一測

試通過。隨意利用順序插入特殊情況是這樣的。在這裏,Django的將調用該函數

views.special_case_2003(request)

/articles/2003 不匹配任何這些模式,因為每個模式要求 URL 以斜線結束。

/articles/2003/03/03/ 將匹配的最終格局。Django 的將調用該函數。

views.article_detail(request,’2003′, ’03’, ’03’)

命名組

上面的例子使用了簡單的,非命名的正則表達式組(通過括號)來捕獲URL的位,並通過他們的位置參數的視圖,在更高級的用法,它可以使用命名正則表達式組成來捕獲URL位,將它們作為關鍵字參數傳遞給視圖。

例子:

from django.conf.urls import url
from .import views
urlpatterns = [
    url(r'^articles/2003/$',views.special_case_2003),
    url(r'^articles/(?P[0-9]{4})/$',views.year_archive),
    url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/(?P[0-9]{2})/$',views.article_detail),
]

這正好完成同樣的事情,前面的例子,一個細微的差別:捕獲的值傳遞給查看功能作為關鍵字參數,而不是位置參數。例如:

請求/articles/2005/03/會調用函數來代替,views.month_archive(request, year=’2005′,month=’03’)views.month_archive(request, ‘2005’, ’03’)
請求/articles/2003/03/03/會調用該函數,views.article_detail(request, year=’2003′,month=’03’, day=’03’)
在實踐中,這意味着你的 URLconf 稍微更明確,不容易參數順序錯誤 – 你可以在你的意見’函數定義重新排序的參數。當然,這些優點來在簡短的費用; 一些開發任務命名組的語法醜陋,太冗長。

匹配/分組算法
這裏的URL配置解析器遵循算法,相對於正則表達式命名組與非命名組:

如果有任何命名參數,它會使用這些,而忽略非命名參數。
否則,它會通過所有非命名參數作為位置參數。
在這兩種情況下,被賦予按任何額外的關鍵字參數傳遞額外的選項來查看功能也將被傳遞給視圖請求/articles/2005/03/會調用函數來代替,views.month_archive(request,year=‘2005’,month=‘03’)

3> What the URLconf searches against
The URLconf searches against the requested URL, as a normal Python string. This does not include GET or POST parameters, or the domain name.

For example, in a request to https://www.example.com/myapp/, the URLconf will look for myapp/.

In a request to https://www.example.com/myapp/?page=3, the URLconf will look for myapp/.

該URL配置不看請求方法。換言之,所有的請求的方法,GET,POST 等將被路由到為相同的URL,相同的功能。

4> 捕獲的參數總是字符串
每個捕獲的參數發送到視圖作為普通的 Python 字符串,無論什麼樣的匹配正則表達式匹配。

例如,在該URL配置行:

url(r’^articles/(?P[0-9]{4})/$’, views.year_archive),
…的 year參數傳遞給 views.year_archive()將是一個字符串,

不是一個整數,即使 [0-9]{4} 將只匹配整数字符串。

5> 指定view的默認設置
一個方便的技巧是你的觀點的論據指定默認參數。下面是一個例子的 RLconf 和看法:

urlconf

from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^blogs/$',views.page),
    url(r'blog/page(?P[0-9]+)/$',views.page),
]

views.py

def page(request,num='1'):
    '''
    處理語句塊
    '''

視圖層

對邏輯負責處理用戶的請求並返回相應,返回可以是HTML內容的網頁,或者重定向,或者錯誤,或者字典

每個應用都有views.py文件

返回快捷鍵功能

render()
render(request,template_name,context=None,content_type=None,status=None,using=None)[source]

結合給定的模板與一個給定的上下文,返回一個字典HttpRespone在渲染文本對象

所需的參數

template_name 一個模板的使用或模板序列名稱全稱。如果序列是給定的,存在於第一個模板將被使用。

可選參數

context 一組字典的值添加到模板中,默認情況下這是一個孔子點

content_type MIME類型用於生成文檔

status 為響應狀態代碼,默認值為200

using這個名字一個模板引擎將使用的模板

例子:

from django.shortcuts import render
def my_view(request):
    return render(request,'myapp/index.html',{'fpp','bar',},content_type='application/xhyml+xml')

重定向

redirect()

redirect(to,permanent=False,*args,**kwargs)[source]
默認情況下,為臨時重定向,通過permanent=True設置永久重定向

例子:

def my_view(request):
    ...
    return redirect('/some/url/')
def my_view(request):
    ...
obj = MyModel.opbjects.get(...)
return redirect(object,permanent=True)

請求和響應對象

django使用請求和響應對象在系統間傳遞狀態

當請求一個頁面時,django創建一個HttpRequest對象包含原數據的請求,然後django加載適當的視圖,通過HttpRequest作為視圖函數的第一個參數,每個視圖負責返回一個HttpResponse目標

HttpRequest對象

HttpRequest.scheme

一個字符串表示請求的計劃方案(HTTP或者HTTPS)

通常HttpRequest.path

一個字符串的完整路徑的請求

HTTPRequest.method

請求HTTP的方法,這裏保證要大寫

#偽代碼
if request.method == 'GET':
    '''
    執行業務代碼
    返回結果
    '''
    return HttpResponse('結果')
#業務邏輯:如果請求來的是GET,你返回個GET字符串
#真代碼
class GETView(objects):
    def getview(self,request):
        if request.method == 'GET':
            return HttpResponse('GET')
  
if request.method == 'GET':
    return HttpResponse('GET')
elif request.method == 'POST':
    return HttpResponse('POST')
elif request.method == 'PUT':
    return HttpResponse('PUT')
elif request.method == 'DELETE':
    return HttpResponse('DELETE')
else:
    return HttpResponse('來了老弟!')

字典包含所有給定的HTTP GET 參數對象

HttpRequest.GET

字典包含所有給定的HTTP POST 參數對象,提供請求包含表單數據

HttpRequest.POST

一個標準的python字典,包含所有的COOKIES,KEY和VALUES都是字符串

字典包含所有上傳的文件

HttpRequest.FILES

語法:

HttpRequest.FILES
filename #上傳的文件名
content_type #上傳文件的類型
content #上傳文件的內容

HttpRequest.META

一個標準的Python字典包含所有可用的HTTP頭,可用標題取決於客戶端和服務器。以下是例子

CONTENT_LENGTH 請求體的長度(一個字符串
CONTENT_TYPE 請求體的類型
HTTP_ACCEPT 為響應–可以接受的內容類型
HTTP_ACCEPT_ENCODING 接受編碼的響應
HTTP_ACCEPT_LANGUAGE 接受語言的反應
HTTP_HOST 客戶端發送的HTTP主機頭
HTTP_REFERER 參考頁面
HTTP_USER_AGENT 客戶端的用戶代理字符串
QUERY_STRING 查詢字符串,作為一個單一的(分析的)字符串
REMOTE_ADDR 客戶端的IP地址
REMOTE_HOST 客戶端的主機名
REMOTE_USER 用戶通過Web服務器的身份驗證
REQUEST_METHOD 字符串,如”GET”或”POST”
SERVER_NAME 服務器的主機名
SERVER_PORT 服務器的端口(一個字符串)

HttpResponse對象

對於HttpRequest 對象來說,是由django自動創建的,但是,HttpResponse 對象就必須我們自己創建。每個 view 請求處理方法必須返回一個 HttpResponse 對象。

HttpResponse 類在 django.http.HttpResponse

字符串使用:
典型的用法是通過頁面的內容,為一個字符串

for django.http import HttpResponse
response = HttpResponse("hello world")
response = HttpResponse("hello world",content_type="text/plain")

如果你想添加內容的增量

response = HttpResponse()
response.write("hello world")
response.write("你好")
#特性與方法:
HttpResponse.content
一個bytestring代表內容HttpResponse.charset

一個字符串的字符集表示的響應將編碼

HttpResponse.status_code

HTTP狀態代碼為響應碼

HttpResponse.streaming

這個屬性永遠為假,一般用於中間件

HttpResponse.closed

方法:

先寫的代碼,后寫的註釋

HttpResponse.__init__(content='',content_type=None,status=200,reason=None,charset=None)[source]
#實例化類自動執行的方法
HttpResponse.__setitem__(header,value)
#為給定值給定的標題名稱,都是字符串
HttpResponse.__delitem__(header)
#刪除標題的名稱,不區分大小寫
HttpResponse.__getitem__(header)
#獲取給定標題名稱。不區分大小寫。
HttpResponse.has_header(header)

#檢查是否具有給定名稱的一個標題
HttpResponse.setdefault(header, value)

#設置一個標題,除非它已經設置。
HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)

#設置一個cookie。參數跟標準庫的Cookie對象差不多
HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=True)

#加密cookice,可以用 HttpRequest.get_signed_cookie() 獲取,當然你也可以加鹽
HttpResponse.delete_cookie(key, path='/', domain=None)

#刪除Cookie與給定鍵。

#HttpResponse子類:
class HttpResponseRedirect[source]

構造函數的第一個參數是必需的路徑redirectto,這是一個完全合格的URL,一個合格的URL(https://www.baidu.com/搜索/),沒有一個絕對的路徑(例如:域搜索//),甚至是相對路徑(如‘/’),

optionalconstructor參數。請注意,這將返回一個HTTP狀態代碼302。
class HttpResponsePermanentRedirect[source]

像httpresponseredirect,但它返回一個永久重定向(HTTP狀態代碼301)而不是“發現”的重定向(狀態代碼302)
class HttpResponseNotModified[source]

構造函數不帶任何參數和NO含量應該被添加到這一反應。使用指定一個頁面沒有被modifiedsince用戶的最後一個請求(狀態代碼304)。
class HttpResponseBadRequest[source]

就像HttpResponse但使用400狀態碼
class HttpResponseNotFound[source]

就像HttpResponse但使用404狀態碼
class HttpResponseForbidden[source]

就像HttpResponse但使用403狀態碼
class HttpResponseNotAllowed[source]

像HttpResponse,但使用405狀態碼。第一argumentto構造函數要求准許清單的方法(如(get,后])
class HttpResponseGone[source]

就像HttpResponse但使用410狀態碼
class HttpResponseServerError[source]

就像HttpResponse但使用500狀態碼

模板層

作為一個Web框架,Django需要模板,模板包含所需的HTML輸出靜態部分以及動態內容插入。
模板的執行
from datetime import datetime
def current_datetime(request):
    now = datetime.datetime.now()
    html = "it is now %s" % now
    return HttpResponse(html)

from django import template
t = template.Templatge("my name is {{name}}")
c = template.Context({"name":"老王"})
print(t.render(c))


import datetime
from django import template
import DjangoDemo.settings
now = datetime.datetime.now()
fp = open(settings.BASE_DIR+"/templates/home/index.html")
t = template.Template(fp.read())
fp.close()
html = t.render(template.Context({'current_date':now}))
return HttpResponse(html)

from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime
def current_datetime(request):
    now = datetime.datetime.now()
    t = get_template('current_datetime.html')
    html = t.render(Content({'current_date':now}))
    return HttpResponse(html)
reurn render_to_response("Account/login.html",data,context_instance=RequestContext(request))

模板語言

模板中也有自己的語言,該語言實現數據展示
{{item}}
{% for item in item_list %}
    {{item}}
{% endfor %}
forloop.counter
forloop.first
forloop.last
{% if ordered_warranty %}
    {% else %}
{% endif %}
母板:{% block title %}{% endblock %}
子板: {% extends"base.html" %}
幫助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}
{{ name|lower }}

自定義simple_tag

在app中創建templatetags模塊

創建任意名字的.py文件

!/usr/bin/env python
coding:utf-8

from django import template
from django.utils.safestring import makesafe
from django.template.base import resolve_variable,Node,TemplateSyntaxError
register = template.Libary()
@register.simple_tag
def my_simple_time(a1,a2,a3):
    return a1+a2+a3
@register.simple_tag
def my_input(id,arg):
    result = "    "%(id,arg)
    return mark_safe(result)

在使用自定義simple_tag的html文件中導入之前創建任意名字的.py文件

{% load xx %}
//使用simple_tag
{% my_simple_time 123 %}

在settings中配置當前app,不然django無法找到自定義的simple_tag

INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01',
)

Models層

Django提供了一個抽象層(Model)的構建和管理Web應用程序的數據

每個模型是一個python類,子類 django.db.models.model

模型中的每個屬性代表數據庫中的一個字段。

例子:

from django.db import models
class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

參數與字段

models.AutoField
#自增=int(11),如果沒有的化,默認會生成一個名稱為id的列,如果要显示的自定義的一個自增列,必須將給列設置為主鍵,主鍵設置方式:primary_key=True
models.CharField
#字符串字符段,必須有max_length參數
models.BooleanField
#布爾類型=tinyint(1),不能為空,Blank=True
models.ComaSeparatedlntegerField
#用逗號分隔的数字=varchar,繼承CharField,所以必須max_length參數
models.DateField
#日期類型 date,對於參數,auto_now=True則每次更新都會更新這個事件,auto_now_add則只是第一次創建添加,之後的更新不再改變
models.DateTimeField
#日期類型 datetime 同DateField參數一樣
models.Decimal
#十進制小數類型=decimal,必須制定整數位max_digits和小數位decimal_places
models.EmailField
#字符串類型(正則表達式郵箱)=varchar,對字符串進行正則表達式
models.FloatField
#浮點類型=double
models.IntegerField
#整型
models.BigIntegerField
#長整型
integer_field_ranges = {
    'SmallIntegerField': (-32768, 32767),
    'IntegerField': (-2147483648, 2147483647),
    'BigIntegerField': (-9223372036854775808, 9223372036854775807),
    'PositiveSmallIntegerField': (0, 32767),
    'PositiveIntegerField': (0, 2147483647),
  }
models.IPAddressField
#字符串類型(ipv4正則表達式)
models.GenericIPAddressField
#字符串類型(ipv4和ivp6是可選的),參數protocol可以是:both、ipv、ipv6,驗證時,會根據設置報錯
models.NullBooleanField
#允許為空的布爾類型
models.PositivenlntegerField
#正integer
models.PositiveSmallIntegerField
#正smallinteger
models.SlugField
#減號、下劃線、字母、数字
models.SmallInterField
#数字,數據庫中的字段有:tinyint、smallint、int、bigint
models.TextField
#字符串=longtext
models.TimeField
#時間 HH:MM[:ss[.uuuuuuu]]
models.URLField
#字符串,地址正則表達式
models.BinaryField
#二進制
models.ImageField
#圖片
models.FilePathField
#文件
null=True
#數據庫中字段是否可以為空
blank=True
#django的Admin中添加數據是是否允許空值
primary_key=False
#主鍵,對AutoField設置主鍵后,就會代替原來的自增id列
auto_now
#自動創建,無論添加或修改,都是當前操作的時間
auto_now_add
#自動創建愛你,永遠是創建時的時間
choices
#choices例子
GENDER_CHOICE = (
(u'M',u'Male'),
(u'F',u'Female'),
)
gender = models.CharField(max_length=2,choices=GENDER_CHOICE)
max_length
default
#默認值
verbose_name
#Admin中字段的显示名稱
nameidb_column
#數據庫中的字段名稱
unique=True
#不允許重複
db_index=True
#數據庫索引
editable=True
#在Admin里是否可編輯
error_messages=None
#錯誤提示
auto_created=False
#自動創建

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

遏制空污 新德里裝空污預警系統

摘錄自2018年10月2日中央社新德里報導

印度新德里空氣污染嚴重程度經常位居世界前幾名,新德里高層官員表示,2018年在進入空污嚴重的冬天前,空污預警系統即將啟用,預計在10月底或11月初安裝,可預測兩天後的空氣品質,以提前遏制空污。

空污系統安裝好後,將從印度中央污染控制局(Central Pollution Control Board,CPCB)、德里污染控制委員會(Delhi Pollution Control Committee)和空氣品質及天氣預測與研究系統機構(System of Air Quality & Weather Forecasting and Research,SAFAR)旗下的36個空氣品質監測站獲得數據,同時從美國國家航空暨太空總署(NASA)衛星獲取即時氣候資料,綜合研判後,對空氣品質進行預測。

協助這項預警系統設置的印度熱帶研究所普恩分所(Indian Institute of Tropical Meteorology-Pune)科學家谷德表示,系統安裝後的第一年,僅空污濃度指標PM2.5(細懸浮微粒)數據被輸入系統,未來幾年將把PM10、二氧化硫(SO2)、二氧化氮(NO2)濃度等數據都納入系統,使空污預測更加準確。

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

Python多線程與隊列

Python多線程與Queue隊列多線程在感官上類似於同時執行多個程序,雖然由於GIL的存在,在Python中無法實現線程的真正并行,但是對於某些場景,多線程仍不失為一個有效的處理方法:

1,不緊急的,無需阻塞主線程的任務,此時可以利用多線程在後台慢慢處理;
2,IO密集型操作,比如文件讀寫、用戶輸入和網絡請求等,此時多線程可以近似達到甚至優於多進程的表現;

多線程的基本使用不再贅述,以下語法便可輕鬆實現:

1 def task(args1, args2):
2     pass
3 
4 Thread(
5     target=task,
6     args=(args1, args2)
7 ).start()

這裏我們重點關注線程通信。

假設有這麼一種場景:有一批源數據,指定一個操作係數N,需要分別對其進行與N的加減乘除操作,並將結果匯總。
當然這裏的加減乘除只是一種簡單處理,在實際的生產環境中,它其實代表了一步較為複雜的業務操作,並包含了較多的IO處理。

自然我們想到可以開啟多線程處理,那麼緊接着的問題便是:如何劃分線程,是根據處理步驟劃分,還是根據源數據劃分?

對於前者,我們把涉及的業務操作單獨劃分位一個線程,即有4個線程分別進行加減乘除的操作,顯然上一個線程的結果是下一個線程的輸入,這類似於流水線操作;

而後者則是把源數據分為若干份,每份啟動一個線程進行處理,最終把結果匯總。一般來說,我們推薦第一種方式。因為在一個線程中完成所有的操作不如每步一個線程清晰明了,

尤其是在一些複雜的場景下,會加大單個線程的出錯概率和測試難度。

那麼我們將開闢4個線程,分別執行加減乘除操作。最後一個除法線程結束則任務完成:

 

 1 #!/usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 
 4 from Queue import Queue
 5 from threading import Thread
 6 
 7 
 8 class NumberHandler(object):
 9     def __init__(self, n):
10         self.n = n
11 
12     def add(self, num):
13         return num + self.n
14 
15     def subtract(self, num):
16         return num - self.n
17 
18     def multiply(self, num):
19         return num * self.n * self.n
20 
21     def divide(self, num):
22         return num / self.n
23 
24 
25 class ClosableQueue(Queue):
26     SENTINEL = object()
27 
28     def close(self):
29         self.put(self.SENTINEL)
30 
31     def __iter__(self):
32         while True:
33             item = self.get()
34             try:
35                 if item is self.SENTINEL:
36                     return
37                 yield item
38             finally:
39                 self.task_done()
40 
41 
42 class StoppableWorker(Thread):
43     def __init__(self, func, in_queue, out_queue):
44         super(StoppableWorker, self).__init__()
45         self.in_queue = in_queue
46         self.out_queue = out_queue
47         self.func = func
48 
49     def run(self):
50         for item in self.in_queue:
51             result = self.func(item)
52             self.out_queue.put(result)
53             print self.func
54 
55 
56 if __name__ == '__main__':
57     source_queue = ClosableQueue()
58     add_queue = ClosableQueue()
59     subtract_queue = ClosableQueue()
60     multiply_queue = ClosableQueue()
61     divide_queue = ClosableQueue()
62     result_queue = ClosableQueue()
63 
64     number_handler = NumberHandler(5)
65 
66     threads = [
67         StoppableWorker(number_handler.add, add_queue, subtract_queue),
68         StoppableWorker(number_handler.subtract, subtract_queue, multiply_queue),
69         StoppableWorker(number_handler.multiply, multiply_queue, divide_queue),
70         StoppableWorker(number_handler.divide, divide_queue, result_queue),
71     ]
72 
73     for _thread in threads:
74         _thread.start()
75 
76     for i in range(10):
77         add_queue.put(i)
78 
79     add_queue.close()
80     add_queue.join()
81     print 'add job done...'
82     subtract_queue.close()
83     subtract_queue.join()
84     print 'subtract job done...'
85     multiply_queue.close()
86     multiply_queue.join()
87     print 'multiply job done...'
88     divide_queue.close()
89     divide_queue.join()
90     print 'divide job done...'
91     result_queue.close()
92 
93     print "%s items finished, result: %s" % (result_queue.qsize(), result_queue)
94 
95     for i in result_queue:
96         print i

運行結果:

線程執行日誌:

 

 

 總的結果:

 

 可見線程交叉運行,但是任務卻是順序結束,這符合我們的預期。

值得注意的是,我們在ClosableQueue定義了一個close()方法,通過放入一個特殊的類變量SENTINEL告訴隊列應該關閉。此外,由於直接加減乘除結果不變,因此我特意乘了兩次來便於我們判斷結果。

總結:

1. Queue是一種高效的任務處理方式,它可以把任務處理流程劃分為若干階段,並使用多條python線程來同時執行這些子任務;

2. Queue類具備阻塞式的隊列操作、能夠指定緩衝區尺寸,而且還支 持join方法,這使得開發者可以構建出健壯的流水線。

 

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!

java property 配置文件管理工具框架,避免寫入 property 亂序

property

是 java 實現的 property 框架。

特點

  • 優雅地進行屬性文件的讀取和更新

  • 寫入屬性文件后屬性不亂序

  • 靈活定義編碼信息

  • 使用 OO 的方式操作 property 文件

  • 支持多級對象引用

變更日誌

快速開始

環境依賴

Maven 3.x

Jdk 1.7+

Maven 引入依賴

<dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>property</artifactId>
    <version>0.0.4</version>
</dependency>

入門案例

讀取屬性

PropertyBs.getInstance("read.properties").get("hello");

read.properties 為文件路徑,hello 為存在的屬性值名稱。

讀取屬性指定默認值

final String value = PropertyBs.getInstance("read.properties")
                .getOrDefault("hello2", "default");

read.properties 為文件路徑,hello2 為不存在的屬性值名稱,default 為屬性不存在時返回的默認值。

設置屬性

PropertyBs.getInstance("writeAndFlush.properties").setAndFlush("hello", "world-set");

writeAndFlush.properties 為文件路徑,hello 為需要設置的屬性信息。

引導類方法概覽

序號 方法 說明
1 getInstance(propertyPath) 獲取指定屬性文件路徑的引導類實例
2 charset(charset) 指定文件編碼,默認為 UTF-8
3 get(key) 獲取 key 對應的屬性值
4 getOrDefault(key, defaultValue) 獲取 key 對應的屬性值,不存在則返回 defaultValue
5 set(key, value) 設置值(內存)
6 remove(key) 移除值(內存)
7 flush() 刷新內存變更到當前文件磁盤
9 flush(path) 刷新內存變更到指定文件磁盤
10 set(map) 設置 map 信息到內存
11 set(bean) 設置 bean 對象信息到內存
12 asMap() 返回內存中屬性信息,作為 Map 返回
13 asBean(bean) 返回內存中屬性信息到 bean 對象中

對象

簡介

我們希望操作 property 可以想操作對象一樣符合 OO 的思想。

設置值

User user = new User();
user.setName("hello");
user.setHobby("hobby");

final long time = 1574147668411L;
user.setBirthday(new Date(time));

PropertyBs propertyBs = PropertyBs.getInstance("setBean.properties")
        .set(user);

Assert.assertEquals("hobby", propertyBs.get("myHobby"));
Assert.assertEquals("1574147668411", propertyBs.get("birthday"));

讀取值

PropertyBs propertyBs = PropertyBs.getInstance("setBean.properties"
        .set("myHobby", "play")
        .set("birthday", "1574147668411");
User user = new User();
propertyBs.asBean(user);
Assert.assertEquals("play", user.getHobby());
Assert.assertEquals(1574147668411L, user.getBirthday().getTime());

對象定義

  • User.java
public class User {

    private String name;

    @PropertyField("myHobby")
    private String hobby;

    @PropertyField(converter = DateValueConverter.class)
    private Date birthday;

}

@PropertyField 註解

序號 屬性 默認值 說明
1 value 當前字段名稱 對應的 property 屬性名稱
2 converter 默認轉換實現 DefaultValueConverter 對當前字段進行屬性的轉換處理

自定義轉換類

  • DateValueConverter.java

這個就是我們針對 Date 類型,自己實現的處理類型。

實現如下:

public class DateValueConverter implements IValueConverter {

    @Override
    public Object fieldValue(String value, IFieldValueContext context) {
        return new Date(Long.parseLong(value));
    }

    @Override
    public String propertyValue(Object value, IPropertyValueContext context) {
        Date date = (Date)value;
        return date.getTime()+"";
    }

}

集合

說明

有時候一個屬性可能是集合或者數組,這裏暫時給出比較簡單的實現。

將字段值直接根據逗號分隔,作為屬性值。

測試案例

UserArrayCollection userArrayCollection = buildUser();
PropertyBs propertyBs = PropertyBs.getInstance("setBeanArrayCollection.properties")
        .set(userArrayCollection);
Assert.assertEquals("array,collection", propertyBs.get("alias"));
Assert.assertEquals("array,collection", propertyBs.get("hobbies"));

對象定義

  • UserArrayCollection.java
public class UserArrayCollection {

    private List<String> alias;

    private String[] hobbies;
}

暫時只支持 String 類型,不想做的過於複雜。

後期將考慮添加各種類型的支持。

多級對象

說明

有時候我們在一個對象中會引用其他對象,比如 對象 a 中包含對象 b。

這裏採用 a.b.c 這種方式作為屬性的 key, 更加符合使用的習慣。

測試案例

設置

Book book = new Book();
book.name("《海底兩萬里》").price("12.34");
UserEntry user = new UserEntry();
user.name("海倫").book(book).age("10");
PropertyBs propertyBs = PropertyBs.getInstance("setBeanEntry.properties")
        .set(user);
Assert.assertEquals("海倫", propertyBs.get("name"));
Assert.assertEquals("10", propertyBs.get("age"));
Assert.assertEquals("《海底兩萬里》", propertyBs.get("book.name"));
Assert.assertEquals("12.34", propertyBs.get("book.price"));

讀取

Map<String, String> map = new HashMap<>();
map.put("name", "海倫");
map.put("age", "10");
map.put("book.name", "《海底兩萬里》");
map.put("book.price", "12.34");
UserEntry userEntry = new UserEntry();
PropertyBs.getInstance("setBeanEntry.properties")
        .set(map)
        .asBean(userEntry);
Assert.assertEquals("UserEntry{name='海倫', age=10, book=Book{name='《海底兩萬里》', price=12.34}}",
        userEntry.toString());

對象定義

  • UserEntry.java
public class UserEntry {

    private String name;

    private String age;

    @PropertyEntry
    private Book book;

}
  • Book.java
public class Book {

    private String name;

    private String price;

}

@PropertyEntry 說明

@PropertyEntry 註解用來標識一個字段是否採用多級對象的方式表示。

這個註解只有一個屬性,就是 value(),可以用來給當前字段指定一個別稱,和 @PropertyField 別稱類似。

後續特性

  • 提供更多內置的類型轉換實現

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

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

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

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

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

※試算大陸海運運費!