利用爬蟲爬取LOL官網上皮膚圖片

  今天在瀏覽網頁時,看到一篇很有意思的文章,關於網絡爬蟲的。該文章是講述如何利用request爬取英雄聯盟官網皮膚圖片。看過文章后覺得挺有用的,把代碼拿過來運行了一下,果真爬取成功。下面給大家分享一下代碼。

  首先得利用cmd命令指示符安裝requests庫,json,re,time。

  安裝完成后,第一步是獲取英雄ID從而為先面判決URL作準備。

def getLOLImages():
    header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'}
    url_js = 'http://lol.qq.com/biz/hero/champion.js'
    #獲取JS源代碼 Str bytes
    res_js = requests.get(url_js).content
    #轉碼 轉成字符串
    html_js = res_js.decode()
    #正則表達式
    req = '"keys":(.*?),"data"'
    list_js = re.findall(req,html_js)
    #轉成dict
    dict_js = json.loads(list_js[0])
    # print(type(dict_js))
    #定義圖片列表
    pic_list = []
    for key in dict_js:
        # print(key)#英雄ID

第二步就是拼接URL了,通過發現英雄皮膚url的取名方式,我們可以方向最後的数字是不同的。讓后通過此方法來獲取圖片地址。

for i in range(20):
    number = str(i)
    if len(number) == 1:
        hero_num = "00"+number
    elif len(number) == 2:
        hero_num = "0"+number
    numstr = key+hero_num
    url = "http://ossweb-img.qq.com/images/lol/web201310/skin/big"+numstr+".jpg"
    #http://ossweb-img.qq.com/images/lol/web201310/skin/big81000.jpg
    pic_list.append(url)

第三步是獲取圖片名稱,path那行是放置圖片的地址,注意結尾的\\不能丟。

list_filepath = []
    path = "D:\Pycharmdaima\Pachong\LOLTU\\"
for name in dict_js.values():
    for i in range(20):
        file_path = path+name+str(i)+'.jpg'
        list_filepath.append(file_path)

第四步就是下載圖片了。

n = 0
for picurl in pic_list:
    res = requests.get(picurl)
    n += 1
    #獲取狀態碼
    if res.status_code == 200:
        print("正在下載%s"%list_filepath[n])
        time.sleep(1)
        with open(list_filepath[n],'wb') as f:
            f.write(res.content)

最後,調用一下getLOLImages()方法

getLOLImages()

  注意,我第一次用了源碼,後來發現運行太慢,檢查一下源碼后發現代碼末尾調用了一個time.sleep()方法。這樣是為了限制爬取速度,避免速度過快被網站發現而中斷。經過調試,我中途暫停代碼運行,將sleep()方法註釋掉,爬取速度果然加快,而且沒有中斷。

  下面是我的爬取成果:

 

 

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

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

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

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

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

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

區塊鏈和分佈式数字賬本正火?如何在7天內快速掌握這些必備的知識

前言

讀研期間,幾次被問到:“什麼是區塊鏈?”“我怎麼學習區塊鏈”。甚至跟“上至九十九”(爺爺奶奶),“下至剛會走的”(小學生的弟弟妹妹)解釋過我的研究內容。因此想總結一份7天的學習計劃(大量資料警告),讓那些對區塊鏈感興趣的人快速入門。區塊鏈技術的被運用到各行各業,尤其是各界(商界和政府)都對區塊鏈技術創新高度重視。本文總結了諸多入門區塊鏈的主要資源,博客、書籍和視頻,希望幫你用7天時間獲取必要的區塊鏈基礎知識。

作者宇宙之一粟,轉載請先聲明出處
公眾號宇宙之一粟,關注公眾號獲取更多相關資源

介紹

區塊鏈,剛開始聽起來會很新穎,因為是一個英文組合詞彙( Block + Chain )。區塊:存放數據的載體(想象成箱子),鏈:把這些箱子首尾相連(類似數據結構中的單鏈表)。

區塊鏈的本質:一個去中心化的分佈式賬本數據庫。其本身是一串使用密碼學相關聯所產生的數據塊,每一個數據塊中包含了多次比特幣網絡交易有效確認的信息。

區塊鏈技術從比特幣中發展而來,是比特幣的底層技術,和比特幣是相伴相生的關係。目前這項技術已經不僅僅限於比特幣——青出於藍而勝於藍。各行各業開始利用這項技術尋求突破。

2019年6月,Facebook宣布了其加密貨幣項目——。

我們國家央行也將發行自己的数字貨幣——( Digital Currency Electronic Payment ),也採用了區塊鏈技術,目前仍處於研究測試過程中。

2019年10月24日下午,。一時間區塊鏈技術又衝上了風口。

因此,我們有必要對區塊鏈技術做一個基本的了解。

如何獲得知識

如果想快速學習區塊鏈知識:收聽音頻課,閱讀書籍,看論文或在線文章,學習白皮書以及參与區塊鏈的相關學習計劃或在線課程。其他針對想從事更加專業的學習人員——參加編程或智能合約編碼課程。

應該學習到什麼程度

在區塊鏈領域工作或打算工作的每個人至少應該能夠理解並編寫一個非常簡單的智能合約,例如以程序語言Solidity通過幾行代碼實現的託管過程。儘管其他人會說,在學習區塊鏈和DLT時應該把重點放在另一個方面,但在我們看來,這是一條清晰的聲明。

在我們看來,理解簡單的智能合約(例如5-10行代碼)的需求不僅對於信息系統領域的員工很重要,而且在商業,經濟和法律領域也很重要。但是,關於如何配置節點的更深入的技術知識通常不是緊要的,但以後可以獲取。

任何尋求參与區塊鏈技術並考慮以下步驟的人都可能擁有光榮的職業生涯。我們認為,區塊鏈技術及其日益重要的潛力有可能對感興趣的人的職業道路產生积極影響,因為在這個動態且快速增長的細分市場中,未來幾年甚至數十年內還有很多工作要做。這樣,可以將由於数字化和自動化程度提高而失業(例如在金融部門)的風險降到最低。

但是感興趣的人如何獲得足夠的知識呢?存在哪些研究區塊鏈技術的機會?本文總結了區塊鏈教育的一些不同策略。我們基本上設計了一個特定的程序,以在大約7個工作日內實現“區塊鏈入門”。

一、購買或轉讓加密貨幣

所需時間:0.5天

除了獲得一些理論知識之外,理解此技術非常重要的是您在操作上“弄髒手”。 它的工作方式如下,為感興趣的人提供有關什麼是區塊鏈技術的最重要學習。

因此,開始的最佳練習是:購買加密貨幣(例如比特幣)並在全球範圍內進行轉移。 如下所示,請找到分步指南:

  • 在例如或比特派上開設一個帳戶;其他選擇:Bitstamp,Bitrex,Binance。
  • 購買比特幣或者購買以太幣。請注意,萬一使用公鑰或私鑰出錯,這筆錢將不可避免地丟失。因此,遵循此步驟當然是每個人自己的決定。
  • 開設第二個帳戶(上面的示例)。
  • 從第二個帳戶獲取一個錢包地址,該地址類似於以太坊的0xd42899dcC146d4788649e6aa5B09f129fC269127。
  • 第一步,將您購買的一部分以太幣或比特幣轉移到該地址。請注意,以太幣和比特幣的地址不同,因此請謹慎行事,切勿混淆。
  • 現在,您可以看到可以在幾秒鐘(以太)或幾分鐘(比特幣)內將價值發送到世界各地。
  • 一個更高級的步驟,但對理解區塊鏈非常有幫助:將插件添加到Google Chrome互聯網瀏覽器中,以直接訪問以太坊網絡並將您的以太幣存儲在您自己的錢包中。之後,開設一個帳戶並生成您自己的錢包地址。然後,將您的一些以太幣從之前的步驟轉移到這個新生成的錢包中。

二、音頻課

所需時間:1.5天

如果你喜歡聽音頻課,選擇一個合適的音頻可以快速入門:

  • Kryptoshow: Julian Hosp博士很好地介紹了區塊鏈技術和加密貨幣這一主題。播客還涵蓋了高級方面,例如在密碼學和編程方面。在訪問播客。
  • BTC Echo:此播客面向更高級的受眾,重點關注比特幣和加密資產。在訪問播客。
  • 從0到1全面學透區塊鏈音頻教程,在學習

三、閱讀重要的白皮書

所需時間:1天

為了了解區塊鏈技術的起源和概念,有必要研究兩種最重要的加密貨幣比特幣和以太坊的白皮書。其他補充Filecoin白皮書。

最重要的論文:

  • 比特幣白皮書:中本聰(2008):比特幣:點對點电子現金系統,。
  • 以太坊白皮書:Buterin,V.(2013):以太坊白皮書:下一代智能合約和去中心化應用平台, 。
  • Filecoin白皮書: Protocol Labs(2017):Filecoin: A Decentralized Storage Network,
    (待完善)

四、觀看視頻

所需時間:2天

在通過閱讀有關比特幣和以太坊的原始著作從“科學”角度看待區塊鏈技術之後,您可以使用視頻進一步熟悉該技術並更深入地了解該技術的不同組成部分。我們推薦以下視頻:

最重要的視頻:

五、更多文章和網站

所需時間:1天

通過遵循建議的步驟,您現在應該已經對技術有了基本的高級知識。現在,是時候更深入地研究區塊鏈技術了。我們建議閱讀以下文章:

文章或文檔:

需要了解的項目的網站:

  • 以太坊:
  • EOS:
  • NULS:
  • FISCO BCOS:

六、更廣泛概述的書籍

所需時間:2天閱讀

其他書籍:

  • 中文版(第2版)
  • Andreas M. Antonopoulos / Gavin Wood(2018年):

Ps: 關注公眾號 宇宙之一粟 回復關鍵字 “區塊鏈” 獲取电子版

七、認識志同道合之人

所需時間:參加2次聚會(主要是免費)

下一步,我們建議您進入區塊鏈社區,並與區塊鏈專家進行首次討論。

科學論文

所需時間:0天,因為這是可選的

如果您打算從科學的角度更多地探討區塊鏈的話題,那麼就有可能研究有關區塊鏈技術的論文。我們將進一步擴大此列表。

文件:

  • Eyal I , Gencer A E , Sirer E G , et al.
  • Gilad, Yossi & Hemo, Rotem & Micali, Silvio & Vlachos, Georgios & Zeldovich, Nickolai. (2017).
  • Li C , Li P , Zhou D , et al.
  • Yin M , Malkhi D , Reiter M K , et al.
  • Wang, Jiaping & Wang, Hao. (2019).
  • 更多區塊鏈相關論文

現在?

重要的是“閱讀”有關區塊鏈和DLT中的教育如何工作的信息。歸根結底,只有一件重要的事情:那就去做。不要只是想,而要行動。

歡迎評論給我,無論您是否遵循我的建議–並向我提供反饋。如果您還有其他想法,請告訴我們如何學習和使用區塊鏈。如果您使用其他來源來獲取或增加您的區塊鏈知識,那麼如果您能與我分享這些知識,我將非常感激。

備註

在Medium看到Education in Blockchain and DLT: How to Acquire the Necessary Knowledge with a Workload of 10 Working Days的一篇博客,但是有很多網站和學習資料使我們不能訪問的。基於此博客,製作了方便我們快速學習並掌握區塊鏈必備知識的這篇文章。

如果您喜歡本文,將其轉發或分享(附上原文出處),我將非常高興並表示感謝。
也歡迎關注我的微信公眾號:宇宙之一粟,分享更多資料,與你讀書學習精進。

參考博客: Authors: Philipp Sandner, Jonas Groß

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

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

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

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

.NET進階篇06-async異步、thread多線程2

知識需要不斷積累、總結和沉澱,思考和寫作是成長的催化劑

內容目錄

一、線程Thread

.NET中線程操作封裝為了Thread類,可以讓開發者對線程進行直觀操作。Thread提供了實例方法用於管理線程的生命周期和靜態方法用於控制線程的一些訪問存儲等一些外在的屬性,相當於工作空間環境變量了

1、生命周期

線程的生命周期有創建、啟動、可能掛起、等待、恢復、異常、然後結束。用Thread類可以容易控制一個線程的全生命周期

Thread類的構造函數重載可以接受ThreadStart無參數和ParameterizedThreadStart有參數的委託,然後調用實例的Start()方法啟動線程。Thread的構造函數的帶有參數的委託,參數是一個object類型,因為我們可以傳入任何信息

Thread t1 = new Thread(() => {
    Console.WriteLine($"新線程  {Thread.CurrentThread.ManagedThreadId.ToString("00")}");
});
t1.Start();
Thread t2 = new Thread((obj) => {
    Console.WriteLine($"新線程  {Thread.CurrentThread.ManagedThreadId.ToString("00")},參數 {obj.ToString()}");
});
t2.Start("hello kitty");

線程啟動后,可以調用線程的Suspend()掛起線程,線程就會處於休眠狀態(不繼續執行線程內代碼),調用Resume()喚醒線程,還有一個不太建議使用的Abort()通過拋出異常的方式來銷毀線程,隨後線程的狀態就會變為AbortRequested

常用的還有線程的等待,在主線程上啟用工作線程后,有時需要等待工作線程的完成后,主線程才繼續工作。可以調用實例方法Join(),當然我們可以傳入時間參數來表明我主線程最多等你多久

2、後台線程

上一章我們知道Thread默認創建的是前台線程,前台線程會阻止系統進程的退出,就是啟動之後一定要完成任務的後台線程會伴隨着進程的退出而退出。通過設置屬性IsBackground=true改為後台線程。另外還可以通過設置Priority指定線程的優先級。但這個並不總會如你所想設置了高優先級就一定最先執行。操作系統會優化調度,這也是線程不太好控制的原因之一

3、靜態方法

上面介紹的都是Tread的實例方法,Thread還有一些常用靜態方法。有時線程設置不當,會有些意想不到的的bug

1.線程本地存儲

AllocateDataSlot和AllocateNamedDataSlot用於給所有線程分配一個數據槽。像下面例子所示,如果不在子線程中給數據槽中放入數據,是獲取不到其他線程往裡面放的數據。

var slot= Thread.AllocateNamedDataSlot("testSlot");
//Thread.FreeNamedDataSlot("testSlot");
Thread.SetData(slot, "hello kitty");
Thread t1 = new Thread(() => {
    //Thread.SetData(slot, "hello kitty");
    var obj = Thread.GetData(slot);
    Console.WriteLine($"子線程:{obj}");//obj沒有值
});
t1.Start();

var obj2 = Thread.GetData(slot);
Console.WriteLine($"主線程:{obj2}");

在聲明數據槽的時候.NET提醒我們如果要更好的性能,請使用ThreadStaticAttribute標記字段。什麼意思?我們來看下面這個例子

//
// 摘要:
//     在所有線程上分配未命名的數據槽。 為了獲得更好的性能,請改用以 System.ThreadStaticAttribute 特性標記的字段。
//
// 返回結果:
//     所有線程上已分配的命名數據槽。
public static LocalDataStoreSlot AllocateDataSlot();

例子中的如果不在靜態字段上標記ThreadStatic輸出結果就會一致。ThreadStatic標記指示各線程的靜態字段值是否唯一

[ThreadStatic]
static string name = string.Empty;
public void Function()
{
    name = "kitty";
    Thread t1 = new Thread(() => {
        Console.WriteLine($"子線程:{name}");//輸出空
    });
    t1.Start();
    Console.WriteLine($"主線程:{name}");//輸出kitty
}

還有一個ThreadLocal提供線程數據的本地存儲,用法和上面一樣,在每個線程中聲明數據僅供自己使用

ThreadLocal<string> local = new ThreadLocal<string>() { };
local.Value = "hello kitty";
Thread t = new Thread(() => {
    Console.WriteLine($"子線程:{local.Value}");
});
t.Start();
Console.WriteLine($"主線程:{local.Value}");

上面的靜態方法用於線程的本地存儲TLS(Thread Local Storage),Thread.Sleep方法在開發調試時也是經常用的,讓線程掛起指定的時間來模擬耗時操作

2.內存柵欄

先說一個常識問題,為什麼我們發布版本時候要用Release發布?Release更小更快,做了很多優化,但優化對我們是透明的(計算機里透明認為是個黑盒子,內部邏輯細節對我們不開放,和生活中透明意味着完全掌握了解不欺瞞剛好相反),一般優化不會影響程序的運行,我們先借用網上的一個例子

bool isStop = false;
Thread t = new Thread(() => {
    bool isSuccess = false;
    while (!isStop)
    {
        isSuccess = !isStop;
    }
});
t.Start();
Thread.Sleep(1000);
isStop = true;
t.Join();
Console.WriteLine("主線程執行結束");

上面例子如果在debug下能正確執行完直到輸出“主程序執行結束”,然而在release下卻一直會等待子線程的完成。這裏子線程中isStop一直為false。首先這是一個由多線程共享變量引起的問題,所以我們建議最好的解決辦法就是盡量不共享變量,其次可以使用Thread.MemoryBarrier和VolatileRead/Write以及其他鎖機制犧牲一點性能來換取數據的安全。(上面例子測試如果在子線程while中進行Console.writeLine操作,奇怪的發現release下也能正常輸出了,猜測應該是進行了內存數據的更新)

release優化會將t線程中的isStop變量的值加載到CPU Cache中,而主線程修改了isStop值在內存中,所以子線程拿不到更新后的值,造成數據不一致。那麼解決辦法就是取值時從內存中獲取。Thread.MemoryBarrier()就可以讓在此方法之前的內存寫入都及時的從CPU Cache中更新到內存中,在此之後的內存讀取都要從內存中獲取,而不是CPU Cache。在例子中的while內增加Thread.MemoryBarrier()就能避免數據不一致問題。VolatileRead/Write是對MemoryBarrier的分開解釋,從處理器讀取,從處理器寫入。

4、返回值

前面聲明線程時,可以傳遞參數,那麼想要有返回值該如何去做呢?Thread並沒有提供返回值的操作,後面.NET給出的對Thead的高級封裝給出了解決方案,直接使用即可。那目前我們使用thread類就要自己實現下帶有返回值的線程操作,都是通過委託實現的,這裏簡單介紹一種,(共享外部變量也是可以,不建議)

private Func<T> ThreadWithReturn<T>(Func<T> func)
{
    T t = default(T);
    Thread thread = new Thread(() =>
    {
        t = func.Invoke();
    });
    thread.Start();
    return () =>

    {
        thread.Join();
        return t;
    };
}
//調用
Func<intfunc = this.ThreadWithReturn<int>(() =>
{
    Thread.Sleep(2000);
    return DateTime.Now.Millisecond;
});
int iResult = func.Invoke();

二、線程池ThreadPool

.NET起初提供Thread線程類,功能很豐富,API也很多,所以使用起來比較困難,況且線程還不都是很像理想中運行,所以從2.0開始提供了ThreadPool線程池靜態類,全是靜態方法,隱藏了諸多Thread的接口,讓線程使用起來更輕鬆。線程池可用於執行任務、發送工作項、處理異步 I/O、代表其他線程等待以及處理計時器

1、工作隊列

常用ThreadPool線程池靜態方法QueueUserWorkItem用於將方法排入線程池隊列中執行,如果線程池中有閑置線程就會執行,QueueUserWorkItem方法的參數可以指定一個回調函數委託並且傳入參數,像下面這樣

ThreadPool.QueueUserWorkItem((obj) => {
                Console.WriteLine($"線程池中線程  {Thread.CurrentThread.ManagedThreadId.ToString("00")} ,傳入 {obj.ToString()}");
            },"hello kitty");

2、工作線程和IO線程

一般異步任務的執行,不涉及到網絡文件等IO操作的,計算密集型,開發者來調用。而IO線程一般用在文件網絡上,是CLR調用的,開發者無需管。工作線程發起文件訪問調用,由驅動器完成后通知IO線程,IO線程則執行異步任務的回調函數

獲取和設置最小最大的工作線程和IO線程

ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
ThreadPool.SetMaxThreads(1616);
ThreadPool.SetMinThreads(88);

3、和Thread區別

如果計算機只有8個核,同時可以有8個任務運行。現在我們有10個任務需要運行,用Thread就需要創建10個線程,用ThreadPool可能只需要利用8個線程就行,節約了空間和時間。線程池中的線程默認先啟動最小線程數量的線程,然後根據需要增減數量。線程池使用起來簡單,但也有一些限制,線程池中的線程都是後台線程,不能設置優先級,常用於耗時較短的任務。線程池中線程也可以阻塞等待,利用ManualResetEvent去通知,但一般不會使用。

4、定時器

.NET中有很多可以實現定時器的功能,在ThreadPool中,我們可以利用RegisterWaitForSingleObject來註冊一個指定時間的委託等待。像下面這樣,將每隔一秒就輸出消息

ThreadPool.RegisterWaitForSingleObject(new AutoResetEvent(true), new WaitOrTimerCallback((obj, b) =>
{
    Console.WriteLine($"obj={obj},tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
}),"hello kitty",1000,false);

我們平常見過比較多的還是timer類,timer類在.net內是好幾個地方都有的,在System.Threading、
System.Timer、System.Windows.Form、System.Web.UI等裏面都有Timer,後面都是在第一個System.Threading里的Timer擴展

System.Threading.Timer timer = new System.Threading.Timer((obj) =>
{
    Console.WriteLine($"obj={obj},tid={Thread.CurrentThread.ManagedThreadId},datetime={DateTime.Now}");
},"hello kitty",1000,1000);

timer的底層有一個TimerQueue,利用ThreadPool.UnsafeQueueUserWorkItem來完成定時功能,和上面我們使用的ThreadPool定時器有一點區別

實際開發中,簡單定時timer就夠用,但一般業務場景比較複雜,需要定製個性化的定時器,比如每月幾號執行,每月第幾個星期幾,幾點執行,工作日執行等。因此我們使用Quarz.NET定時框架,後面框架整合時會用到,用起來也是很簡單的

先就啰嗦這兩點吧,下一篇應該是Task、Parallel以及Async/Await,然後總結介紹下C#的線程模式、線程同步鎖機制、異常處理,線程取消,線程安全集合和常見的線程問題

天長水闊,見字如面,隨緣更新,拜了個拜~

可關注主頁公號獲取更多哈

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

【其他文章推薦】

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

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

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

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

Ansibile之playbook初識

  一、playbook簡介

  ansiblie的任務配置文件被稱為playbook,俗稱“劇本”,每一個劇本(playbook)中都包含了一系列的任務,這每個任務在ansible中又被稱為“戲劇”(play),一個劇本中包含多齣戲劇。。

  前文我們了解了ansible有兩種執行方式ad-hoc和ansible-playbook,ad-hoc主要用於臨時命令的執行,而playbook我們可以理解為ad-hoc的集合,有點類似shell腳本,ad-hoc就相當於shell腳本里的某條任務語句,playbook就相當於整個shell腳本。playbook是由一個或多個“play”組成的列表,play的主要功能在於將預定義的一組主機,裝扮成事先通過ansible中的task定義好的角色。task實際是調用ansible的一個模塊,將多個play組織在一個playbook中,即可以讓他們聯合起來,按事先編排的機制執行預定義的動作。

 如以上圖示,用戶可以把多條任務(ad-hoc任務)寫到playbook中,用戶用ansible-playbook命令調用執行編排好的playbook,ansible會讀取playbook中的每一條play和task,並按照playbook中的順序從上至下依次執行,ansible會調用每個task中定義的模塊去依次執行相應的任務,並按照playbook中指定的主機去主機清單里匹配對應的主機,然後通過ssh認證,把編譯好的相應的任務文件發送到對應的主機或網絡設備上執行,最後返回執行的狀態。

  二、YAML簡介

  playbook採用yaml語言編寫,yaml是一個可讀性高的用來表達資料序列格式的語言,它參考了其他很多種語言,包括:XML、C語言、python、perl以及电子郵箱格式RFC2822等。Clark Evans在2001年首次發表了這種語言,另外Ingy döt Net與Oren Ben-Kiki也是這語言的共同設計者。YAML( YAML Ain’t Markup Language),即yaml不是標記語言。不過在開發這種語言時,yaml的意思其實是:”Yet Another Markup Language”(仍是一種標記語言)

  ymal特性

  1)YAML的可讀性好

  2)YAML和腳本語言的交互性好

  3)YAML使用實現語言的數據類型

  4)YAML有一個一致的信息模板

  5)YAML易於實現,可以基於流程處理,表達能力強,擴展性好

更多的內容及規範請參考官方文檔

  三、playbook語法簡介

  1)需要以“—”(3個減號)開始,且需頂行首寫。另外還有選擇性的連續三個點號(…)用來表示文件的結尾。

  2)次行開始正常寫playbook的內容,建議次行寫該playbook的功能,當然不寫也是可以的。

  3)使用“#”號註釋代碼。

  4)縮進必須統一,不能空格tab混用。

  5)縮進的級別必須是一致的,同樣的縮進代表同樣級別,程序判別配置的級別是通過縮進結合換行來實現的。

  6)YAML文件內容和Linux系統大小寫判斷方式一直,區分大小寫(大小寫敏感),k/v的值均大小寫敏感。

  7)k/v的值可同行寫也可換行寫。同行使用“:”分隔,換行寫需要以“-”分隔。

  8)v可以是字符串,也可以另外一個列表,當然也可以是字典。

  9)一個完整的代碼塊功能最少需要有name:xxx(對任務的描述)。

  10)一個name只能包括一個task

  11)yaml文件擴展名通常為yml或yaml

list:列表,其所有元素均使用“-”開頭

示例:

---
# A list of tasty fruits

- apple
- orange
- strawberry
- mango
~           

dictionary:字典,通常由多個key與value構成

示例:

---
#An employee record
name: example developer
job: developer
skill: elite  

當然也可以將key:value放置於{}中進行表示,用“,”分隔多個key:value

示例:

---
#An employee record
{name: example developer,job: developer, skill: elite}
~                                                         

  YAML的語法和其他高階語言類似,並且可以簡單表達清單、散列表、標量等數據結構。其結構(Structure)通過空格來展示,序列(Sequence)里的項用”-“來代表,Map里的鍵值對用”:”分隔。

示例:

---
name: John Smith
age: 41
gender: Male
spouse:
  name: Jane Smith
  age: 37
  gender: Female
children:
  - name: Jimmy Smith
    age: 17
    gender: Male
  - name: Jenny Smith
    age: 13
    gender: Female
~                    

  四、playbook核心元素

  1)hosts  :指定執行任務的遠程主機列表(主機清單定義的主機組或單個主機,支持前面的說的主機模式匹配)

  2)tasks  :任務集

  3)varniables  :內置變量或自定義變量在playbook中調用

  4)templates  :模板,可替換模板文件中的變量並實現一些簡單邏輯的文件

  5)handlers  和  notity結合使用,由特定條件出發的操作,滿足條件方才執行,否則不執行

  6)tags標籤  :給指定的任務貼上標籤,我們在執行playbook的時候可以根據標籤選擇性的挑選部分代碼執行,如 ansible-playbook -t tagsname useradd.yml  ,這條命令的意思就是在useradd.yml中挑選標籤名為tagsname的任務執行

   五、playbook基礎組件

  1)hosts:

    playbook中的每一個play的目的都是為了讓特定主機以某個指定的用戶身份執行任務。hosts用於指定要執行任務的主機,須事先定義在主機清單中。hosts指定主機的形式同樣支持像主機清單中定義的那樣,支持通配,支持主機模式匹配與或非,支持IP地址,當然也支持混合匹配與或非。

示例:在websers組,但不再dbsers組,可以這樣定義hosts

---
- hosts: websers:!dbsers

  2)remote_user:可用於host和task中,也可以通過指定其通過sudo的方式在遠程執行任務,其可用於play全局或某個任務;此外,甚至可以在sudo時使用用sudo_user指定sudo時切換的用戶,如下所示

---
- hosts: websers:!dbsers
  remote_user: root

  tasks:
    - name: test connection
      ping:
      remote_user: qiuhom
      sudo: yes
      sudo_user: qiuping

  說明:默認sudo 為root,上例指定了sudo_user 為qiuping,上述任務同sudo -u qiuping ping xxxx(代表某主機)命令一樣的意思,當然在使用sudo 時 我們還需要在目標主機上對qiuhom授權,要讓qiuhom這個用戶具有代表qiuping的權限去執行ping命令。

  3)task列表和action:play的主體部分是task list,task list 中的各任務按次序逐個在hosts中指定的所有主機上執行,即在所有主機上完成第一個任務后,再開始第二個任務;task的目的是使用指定的參數執行模塊,而在模塊參數中可以使用變量,模塊執行時是冪等的,這意味着多次執行時是安全的,其結果均一致;每個task都應該有其name,用於playbook的執行結果輸出,建議其內容能清晰地描述任務步驟,如未提供name,則action的結果將用於輸出。

  tasks:任務列表,它有兩種格式如下

    (1)action: module arguments

    (2)module: arguments        ##建議使用

   注意:shell模塊和command模塊後面跟的是命令,而非key=value

如果某項任務的狀態在運行後為changed時,可通過“notify”通知給相應的handlers;當然任務可以通過“tags”打標籤,可以在ansible-playbook命令上使用-t指定進行指定其標籤名調用。

示例:

[qiuhom@test ~]$cat test.yml 
---
- hosts: websers:!dbsers
  remote_user: root

  tasks:
    - name: test connection
      ping:
      remote_user: qiuhom
      sudo: yes
      sudo_user: qiuping 
      tags: test
    - name: test command
      shell: /bin/ls /home/qiuhom/
[qiuhom@test ~]$ansible-playbook -t test test.yml 

  說明:用-t 指定標籤名,表示只運行所指定標籤所在的任務,當然同名的標籤可以在多條任務中,一個任務也可以有多個標籤。

如果命令或腳本的退出碼不為零,可用使用如下方式忽略或跳過繼續執行以下代碼

---
- hosts: websers:!dbsers
  remote_user: root

  tasks:
    - name: run this command and ignore the result
      shell: /usr/sbin/ip addr show eth0 || /bin/true
    - name: run this command and ignore the result
      shell: /usr/sbin/ip addr show eth0
      ignore_errors: True

  說明:兩種方式都可以跳過出錯的命令而不打斷playbook,繼續執行以下的代碼,前者使用的短路或的特性,後者使用ignore_errors參數來控制

  六、playbook運行的方式

ansible-playbook <filename.yml> ... [options]

常用選項:

  -C , –check  : 只檢查可能會發生的改變,但不真正執行操作,相當於空跑一遍playbook,測試下是否和自己預想的結果一樣,但它不會真正的去遠端主機上執行。常用於測試寫的playbook語法是否有誤。

  –list-hosts  :列出playbook指定運行任務所匹配的主機

  –list-tags    :列出playbook中所有標籤名稱列表

  –list-tasks  :列出playbook中所有任務名稱及標籤名稱

  –limit 主機列表   :只針對指定主機列表中的主機執行當前playbook(指定主機列表必須是在playbook里定義的主機列表範圍內)

  -v,-vv,-vvv       :  显示執行playbook的過程,-v,显示較簡單,-vv显示較詳細,-vvv显示整個過程(非常詳細)

[root@test ~]#cat test.yml 
---
- hosts: websers
  remote_user: root

  tasks:
    - name: run this command 
      shell: hostname
      tags: hostname
      ignore_errors: True
    - name: show ip addr
      shell: /sbin/ip addr show
      tags: showip
[root@test ~]#ansible-playbook test.yml --list-hosts

playbook: test.yml

  play #1 (websers): websers    TAGS: []
    pattern: [u'websers']
    hosts (2):
      192.168.0.128
      192.168.0.218
[root@test ~]#ansible-playbook test.yml --list-tags

playbook: test.yml

  play #1 (websers): websers    TAGS: []
      TASK TAGS: [hostname, showip]
[root@test ~]#ansible-playbook test.yml --list-tasks

playbook: test.yml

  play #1 (websers): websers    TAGS: []
    tasks:
      run this command  TAGS: [hostname]
      show ip addr      TAGS: [showip]
[root@test ~]#ansible-playbook test.yml --limit 192.168.0.218

PLAY [websers] ********************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [192.168.0.218]

TASK [run this command] ***********************************************************************************************
changed: [192.168.0.218]

TASK [show ip addr] ***************************************************************************************************
changed: [192.168.0.218]

PLAY RECAP ************************************************************************************************************
192.168.0.218              : ok=3    changed=2    unreachable=0    failed=0   

[root@test ~]#ansible-playbook test.yml --limit 192.168.0.218 -v
Using /etc/ansible/ansible.cfg as config file

PLAY [websers] ********************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************
ok: [192.168.0.218]

TASK [run this command] ***********************************************************************************************
changed: [192.168.0.218] => {"changed": true, "cmd": "hostname", "delta": "0:00:00.002139", "end": "2019-11-16 23:11:02.996962", "rc": 0, "start": "2019-11-16 23:11:02.994823", "stderr": "", "stderr_lines": [], "stdout": "localhost.localdomain", "stdout_lines": ["localhost.localdomain"]}

TASK [show ip addr] ***************************************************************************************************
changed: [192.168.0.218] => {"changed": true, "cmd": "/sbin/ip addr show", "delta": "0:00:00.002604", "end": "2019-11-16 23:11:03.733004", "rc": 0, "start": "2019-11-16 23:11:03.730400", "stderr": "", "stderr_lines": [], "stdout": "1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN \n    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n    inet6 ::1/128 scope host \n       valid_lft forever preferred_lft forever\n2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000\n    link/ether 00:0c:29:e8:f6:7b brd ff:ff:ff:ff:ff:ff\n    inet 192.168.0.218/24 brd 192.168.0.255 scope global eth0\n    inet6 fe80::20c:29ff:fee8:f67b/64 scope link \n       valid_lft forever preferred_lft forever\n3: pan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN \n    link/ether d2:7a:38:cf:27:60 brd ff:ff:ff:ff:ff:ff", "stdout_lines": ["1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN ", "    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00", "    inet 127.0.0.1/8 scope host lo", "    inet6 ::1/128 scope host ", "       valid_lft forever preferred_lft forever", "2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000", "    link/ether 00:0c:29:e8:f6:7b brd ff:ff:ff:ff:ff:ff", "    inet 192.168.0.218/24 brd 192.168.0.255 scope global eth0", "    inet6 fe80::20c:29ff:fee8:f67b/64 scope link ", "       valid_lft forever preferred_lft forever", "3: pan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN ", "    link/ether d2:7a:38:cf:27:60 brd ff:ff:ff:ff:ff:ff"]}

PLAY RECAP ************************************************************************************************************
192.168.0.218              : ok=3    changed=2    unreachable=0    failed=0   

[root@test ~]#

  說明:–limit 所指定的主機必須是在playbook中所指定的主機範圍內。

   七、playbook vs shell scripts

  1)shell腳本如下:

#!/bin/bash
# 安裝Apache
yum install --quiet -y httpd
# 複製配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 啟動Apache,並設置開機啟動
service httpd start
chkconfig httpd on

  2)playbook

---
- hosts: websers
  remote_user: root

  tasks:
    - name: create apache group
      group: name=apache gid=80 system=yes
    - name: create apache user
      user: name=apache uid=80 group=apache system=yes shell=/sbin/nologin home=/var/www/html 
    - name: install httpd
      yum: name=httpd
    - name: copy config file
      copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
    - name: copy config 2 file
      copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
    - name: start httpd service
      service: name=httpd state=started enabled=yes     

  說明:兩者都是實現同樣的目的,很明顯playbook的優勢要比腳本的優勢多,playbook 可以針對很多台主機進行任務執行,而腳本只可以在某一台主機上執行;腳本重複執行沒有冪等性,很有可能帶來很多錯誤,而playbook卻不會有這樣的苦惱。

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

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

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

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

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

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

快速搭建Jenkins集群

關於Jenkins集群

在Jenkins上同時執行多個任務時,單機性能可能達到瓶頸,使用Jenkins集群可以有效的解決此問題,讓多台機器同時處理這些任務可以將壓力分散,對單機版Jenkins的單點故障的隱患也有分散作用,今天就來實戰快速搭建Jenkins集群,Jenkins版本是2.190.2;

如何做到快速搭建集群

通過Docker可以省去大部分準備工作,您只需在Linux電腦上安裝docker,在輔以少量命令和操作即可完成集群搭建;

環境信息

本次實戰的環境一共要用三台電腦,它們的設置都是一樣的,如下:

  1. 操作系統:CentOS Linux release 7.6.1810
  2. 防火牆關閉
  3. docker:1.13.1

三台電腦的信息如下:
| 主機名 | IP地址 | 作用 |
|–|–|–|
| master | 192.168.133.131 | Jenkins集群的master節點,提供web服務 |
| agent1 | 192.168.133.132 | Jenkins集群的一號工作接節點,標籤是maven |
| agent2 | 192.168.133.133 | Jenkins集群的二號工作接節點,標籤是gradle |

建議agent2節點的內存大於4G,因為下一篇的實戰操作會用agent2編譯構建spring-framework,對內存的需求略大;

準備工作

  1. 後面的所有操作都是root賬號;
  2. 在每台電腦上創建文件夾/usr/local/jenkins

    創建Jenkins的master

  3. 登錄master機器,執行以下命令:
docker run \
  -u root \
  -idt \
  --name master \
  -p 8080:8080 \
  -p 50000:50000 \
  -v /usr/local/jenkins:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  jenkinsci/blueocean:1.19.0
  1. 執行docker logs master,會在控制台显示jenkins的登錄秘鑰,如下圖紅框所示:
  2. 瀏覽器輸入地址: ,显示Jenkins登錄頁面,如下圖所示,在紅框位置輸入剛才複製的登錄秘鑰即可登錄:
  3. 選擇安裝推薦的插件
  4. 靜候插件在線安裝完成:
  5. 接下來是創建管理員和使用實例url的操作,這裏就不多說了,您按實際情況自行斟酌;

    至此,Jenkins的master已經搭建好,接下來將agent1和agent2作為工作節點加入集群;

    加入agent1

  6. 在Jenkins網頁上新增節點,操作如下圖,先進入節點管理頁面:
  7. 如下圖,新增一個節點,名為agent1
  8. 接下來的節點詳情信息如下圖,注意四個紅框中的內容要和圖中保持一致:
  9. 保存成功後會显示機器列表,如下圖,圖標上的紅叉表示機器不在線(此時agent1還沒有接入),點擊紅框:
  10. 如下圖所示,紅框中的命令就是agent1的啟動命令,執行該命令的機器會以agent1的身份加入集群:
  11. 注意上圖紅框中的agent.jar是個名為agent.jar的文件的下載鏈接,將此文件下載到agent1電腦的/usr/local/jenkins目錄下;
  12. ssh登錄agent1電腦,執行以下命令,即可將agent1加入Jenkins集群:
docker run \
  -u root \
  -idt \
  --name agent \
  -v /usr/local/jenkins:/usr/local/jenkins \
  bolingcavalry/openjdk-with-sshpass:8u232 \
  java -jar /usr/local/jenkins/agent.jar \
  -jnlpUrl http://192.168.133.131:8080/computer/agent1/slave-agent.jnlp \
  -secret 44c3e8d1531754b8655b53294bbde6dd99b3aaa91a250092d0d3425534ae1058 \
  -workDir "/usr/local/jenkins"

上述命令中的後半部分,即java -jar ……就是前面圖片紅框中的agent1啟動命令,唯一要改變的是將agent.jar改成絕對路徑/usr/local/jenkins/agent.jar

  1. 上述命令的鏡像是bolingcavalry/openjdk-with-sshpass:8u232,其Dockerfile內容如下,可見非常簡單,就是OpenJDK鏡像裏面安裝了sshpass,這樣的容器可以在執行ssh命令時帶上遠程機器的密碼,而不用等待用戶輸入密碼,這樣便於shell腳本執行ssh命令:
FROM openjdk:8u232

ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install --assume-yes sshpass
  1. 去Jenkins的網頁上查看節點列表,如下圖,可見agent1已經成功加入:

    加入agent2

    agent2加入集群的方式和agent1大部分是一樣的,只有以下兩點要注意:

  2. 在Jenkins頁面上創建節點,名稱是agent2
  3. agent2的標籤是gradle,如下圖紅框所示:
  4. 此時agent2也加入成功:

    至此,Jenkins集群搭建完成,這兩個節點帶有不同的標籤,下一篇文章中,我們在這個集群環境創建pipeline任務,並通過標籤被分配到不同的節點上,實現多節點并行執行;

    歡迎關注公眾號:程序員欣宸

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

【其他文章推薦】

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

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

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

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

數據結構之隊列and棧總結分析

一、前言:

  數據結構中隊列和棧也是常見的兩個數據結構,隊列和棧在實際使用場景上也是相輔相成的,下面簡單總結一下,如有不對之處,多多指點交流,謝謝。

二、隊列簡介

  隊列顧名思義就是排隊的意思,根據我們的實際生活不難理解,排隊就是有先後順序,先到先得,其實在程序數據結構中的隊列其效果也是一樣,及先進先出。

     隊列大概有如下一些特性:

     1、操作靈活,在初始化時不需要指定其長度,其長度自動增加(默認長度為32)

        注:在實際使用中,如果事先能夠預估其長度,那麼在初始化時指定長度,可以提高效率

        2、泛型的引入,隊列在定義時可以指定數據類型避免裝箱拆箱操作

     3、存儲數據滿足先進先出原則

       

   c#中有關隊列的幾個常用方法:

    • Count:Count屬性返回隊列中元素個數。
    • Enqueue:Enqueue()方法在隊列一端添加一個元素。
    • Dequeue:Dequeue()方法在隊列的頭部讀取和刪除元素。如果在調用Dequeue()方法時,隊列中不再有元素,就拋出一個InvalidOperationException類型的異常。
    • Peek:Peek()方法從隊列的頭部讀取一個元素,但不刪除它。
    • TrimExcess:TrimExcess()方法重新設置隊列的容量。Dequeue()方法從隊列中刪除元素,但它不會重新設置隊列的容量。要從隊列的頭部去除空元素,應使用TrimExcess()方法。
    • Clear:Clear()方法從隊列中移除所有的元素。
    • ToArray:ToArray()複製隊列到一個新的數組中。

  下面通過隊列來實例模擬消息隊列的實現流程:

 

using System;
using System.Collections;
using System.Collections.Generic;

namespace dataStructureQueueTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("通過Queue來模擬消息隊列的實現");
            QueueTest queueTest = new QueueTest();

            while (true)
            {
                Console.WriteLine("請輸入你操作的類型:1:代表生成一條消息,2:代表消費一條消息");
                string type = Console.ReadLine();
                if (type == "1")
                {
                    Console.WriteLine("請輸入具體消息:");
                    string inforValue = Console.ReadLine();
                    queueTest.InformationProducer(inforValue);
                }
                else if (type == "2")
                {
                    //// 在消費消息的時候,模擬一下,消費成功與消費失敗下次繼續消費的場景

                    object inforValue = queueTest.InformationConsumerGet();
                    if (inforValue == null)
                    {
                        Console.WriteLine("當前無可消息可消費");
                    }
                    else
                    {
                        Console.WriteLine("獲取到的消息為:" + inforValue);

                        Console.WriteLine("請輸入消息消費結果:1:成功消費消息,2:消息消費失敗");
                        string consumerState = Console.ReadLine();

                        ///// 備註:該操作方式線程不安全,在多線程不要直接使用
                        if (consumerState == "1")
                        {
                            queueTest.InformationConsumerDel();
                        }
                    }
                }
                else
                {
                    Console.WriteLine("操作有誤,請重新選擇");
                }
            }
        }
    }

    /// <summary>
    /// 隊列練習
    /// </summary>
    public class QueueTest
    {
        /// <summary>
        /// 定義一個隊列
        /// </summary>
        public Queue<string> queue = new Queue<string>();

        /// <summary>
        /// 生成消息--入隊列
        /// </summary>
        /// <param name="inforValue"></param>
        public void InformationProducer(string inforValue)
        {
            queue.Enqueue(inforValue);
        }

        /// <summary>
        /// 消費消息---出隊列--只獲取數據,不刪除數據
        /// </summary>
        /// <returns></returns>
        public object InformationConsumerGet()
        {
            if (queue.Count > 0)
            {
                return queue.Peek();
            }

            return null;
        }

        /// <summary>
        /// 消費消息---出隊列---獲取數據的同時刪除數據
        /// </summary>
        /// <returns></returns>
        public string InformationConsumerDel()
        {
            if (queue.Count > 0)
            {
                return queue.Dequeue();
            }

            return null;
        }
    }
}

 

 

三、棧簡介

  棧和隊列在使用上很相似,只是棧的數據存儲滿足先進后出原則,棧有如下一些特性:

     1、操作靈活,在初始化時不需要指定其長度,其長度自動增加(默認長度為10)

        注:在實際使用中,如果事先能夠預估其長度,那麼在初始化時指定長度,可以提高效率

        2、泛型的引入,棧在定義時可以指定數據類型避免裝箱拆箱操作

     3、存儲數據滿足先進后出原則

    c#中有關棧的幾個常用方法:

  • Count:Count屬性返回棧中的元素個數。
  • Push:Push()方法在棧頂添加一個元素。
  • Pop:Pop()方法從棧頂刪除一個元素,並返回該元素。如果棧是空的,就拋出一個InvalidOperationException類型的異常。
  • Peek:Peek()方法返回棧頂的元素,但不刪除它。
  • Contains:Contains()方法確定某個元素是否在棧中,如果是,就返回true。

     下面通過一個棧來模擬瀏覽器的回退前進操作的實現

 

using System;
using System.Collections.Generic;

namespace dataStructureStackTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //// 通過棧來模擬瀏覽器回退前進操作
            ////   1、定義兩個棧,分別記錄回退的地址集合,和前進地址集合
            ////   2、在操作具體的回退或者前進操作時
            ////      如果和前一次操作相同,那麼就取出對應隊列的一條數據存儲到另外一個隊列
            Console.WriteLine("本練習模擬瀏覽器的回退前進操作:");

            /// 假設瀏覽器已瀏覽了20個網站記錄
            StackTest stackTestBack = new StackTest(20);
            StackTest stackTestGo = new StackTest(20);
            for (int i = 0; i < 20; i++)
            {
                stackTestBack.PushStack("網站" + (i + 1).ToString());
            }

            //// 記錄上一次操作
            string beforOpert = "";
            while (true)
            {
                Console.WriteLine("");
                Console.WriteLine("請輸入你操作的類型:1:回退,2:前進");
                string type = Console.ReadLine();

                if (type == "1")
                {
                    //// 出棧
                    if (beforOpert == type)
                    {
                        stackTestGo.PushStack(stackTestBack.GetAndDelStack());
                    }
                    string wbeSit = stackTestBack.GetStack();
                    Console.WriteLine("回退到頁面:" + wbeSit);
                    beforOpert = type;
                }
                else if (type == "2")
                {
                    //// 出棧
                    if (beforOpert == type)
                    {
                        stackTestBack.PushStack(stackTestGo.GetAndDelStack());
                    }
                    string wbeSit = stackTestGo.GetStack();

                    Console.WriteLine("回退到頁面:" + wbeSit);
                    beforOpert = type;
                }
                else
                {
                    Console.WriteLine("請輸入正確的操作方式!!");
                }
            }
        }
    }

    /// <summary>
    /// 隊列練習
    /// </summary>
    public class StackTest
    {
        /// <summary>
        /// 定義一個棧
        /// </summary>
        public Stack<string> stack;

        /// <summary>
        ///無參數構造函數,棧初始化為默認長度
        /// </summary>
        public StackTest()
        {
            stack = new Stack<string>();
        }

        /// <summary>
        ///有參數構造函數,棧初始化為指定長度
        ///如果在定義隊列時,如果知道需要存儲的數據長度,那麼最好預估一個長度,並初始化指定的長度
        /// </summary>
        public StackTest(int stackLen)
        {
            stack = stackLen > 0 ? new Stack<string>(stackLen) : new Stack<string>();
        }

        /// <summary>
        /// 入棧
        /// </summary>
        /// <param name="inforValue"></param>
        public void PushStack(string inforValue)
        {
            stack.Push(inforValue);
        }

        /// <summary>
        /// 出棧(但不刪除)
        /// </summary>
        /// <returns></returns>
        public string GetStack()
        {
            if (stack.Count > 0)
            {
                return stack.Peek();
            }

            return null;
        }

        /// <summary>
        /// 出棧(並刪除)
        /// </summary>
        /// <returns></returns>
        public string GetAndDelStack()
        {
            if (stack.Count > 0)
            {
                return stack.Pop();
            }

            return null;
        }
    }
}

 

四、使用場景總結

  根據隊列和棧的特點,下面簡單總結一下隊列和棧的一些實際使用場景

   隊列:

    1、異步記錄日誌,此處會涉及到單例模式的使用

    2、消息隊列

    3、業務排隊,比如12306車票購買排隊等候

    4、其他符合先進先出原則的業務操作

   棧:

    1、可回退的操作記錄,比如:瀏覽器的回退操作

    2、計算表達式匹配,比如:計算器表達式計算

    3、其他符合先進后出原則的業務操作

 

附件:

關於這一些練習的代碼,上傳到github,有興趣的可以看一下:

 

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

【其他文章推薦】

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

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

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

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

盤點2016年起實施的新能源汽車新政策

電動汽車充電介面及通信協定5項新國標  

第一版電動汽車充電介面等4項國家標準曾在2011年發佈,並於2012年3月1日起實施,包括《電動汽車傳導充電用連接裝置第1部分:通用要求》、《電動汽車傳導充電用連接裝置第2部分:交流充電介面》、《電動汽車傳導充電用連接裝置第3部分:直流充電介面》《電動汽車非車載傳導式充電機與電池管理系統之間的通信協定》等。此次發佈的5項國家標準在4項標準的修訂基礎上新增《電動汽車傳導充電系統 第1部分:一般要求》,於2016年1月1日起正式實施。

標準內容:新修訂的5項國家標準主要在提高電動汽車充電設施安全性及相容性方面做出更進一步的要求。

交流充電部分,更新禁止採用存在安全隱患的直通電纜加普通家用插頭的連接方式,大於16安培的充電方式要求在車輛插座和供電插座安裝電子鎖和溫度感測器等規範。

 

直流充電部分,更新在直流充電槍內要求安裝電子鎖,同時預留車輛插座加裝電子鎖的機械結構,要求車輛和設施必須具備檢測和告警功能等規範。

 

新能源車補貼政策  

2015年4月29日,新一輪新能源汽車補貼政策正式出臺,其中指出在2016-2020年,對消費者購買的進入國家新能源車目錄的純電動汽車、插電式混合動力汽車和燃料電池汽車繼續給予購車補貼。新標準規定新能源車的補貼將分階段退坡,到2020年補貼標準將在2016年基礎上下降40%。

政策內容:新的補貼標準將依據節能減排效果,並綜合考慮生產成本、規模效應、技術進步等因素逐步下調。具體下調辦法是,2017-2018年補貼標準將在2016年基礎上下降20%,2019-2020年補貼標準在2016年基礎上下降40%。而燃料電池汽車的補貼將從2015年的18萬元/輛提升至20萬元/輛。

 對比2013—2015年新能源車補貼標準,2016年起執行的新補貼標準針對續駛里程大於等於80km小於150km的純電動車和增程式在內的插電式混合動力乘用車的補貼金額分別降低了6500元和1500元,而續駛里程大於等於250km的電動車和燃料電池乘用車補貼金額分別提高了1000元和2萬元,因而您在購買新能源車的時候,續駛里程將是非常關鍵的價格影響因素。

新補貼標準對補助範圍內的新能源汽車產品技術的要求也有所提高,其中純電動乘用車的最低續駛里程由大於等於80km提升至100km,同時在行駛速度方面,純電動乘用車30分鐘最高車速應不低於100km/h。

車船稅管理新規  

規程內容:規程中指出,已經繳納車船稅的車船,因品質原因,車船被退回生產企業或者經銷商的,納稅人可以向納稅所在地的主管稅務機關申請退還自退貨月份起至該納稅年度終了期間的稅款,退貨月份以退貨發票所載日期的當月為准。

此外,已完稅車輛被盜搶、報廢、滅失而申請車船稅退稅的,由納稅人納稅所在地的主管稅務機關按照有關規定辦理。

而對不屬於車船稅徵稅範圍的純電動乘用車和燃料電池乘用車,應當積極獲取車輛的相關資訊予以判斷,對其徵收了車船稅的應當及時予以退稅。

第四階段乘用車燃料消耗量限值  

政策內容:2012年6月28日,國務院發佈《節能與新能源汽車產業發展規劃(2012-2020年)》,明確了我國汽車節能標準的整體目標,要求2020年當年乘用車新車平均燃料消耗量達到5.0 L/100km。目前,第四階段的GB 19578-2014《乘用車燃料消耗量限值》和GB 27999-2014《乘用車燃料消耗量評價方法及指標》已於2014年12月22日正式發佈,於2016年1月1日起實施,要求汽車生產企業2016年平均燃料消耗標準需滿足6.7L/100km。

除了以上提到的自2016年1月1日起實施的政策外,還有一些和我們密切相關的政策和措施已在2015年的最後一天終止或完成,讓我們也來關注一下。

節能惠民補貼政策到期取消

政策內容:2013年,國家財政部、發展改革委、工業和資訊化部發佈《關於開展1.6升及以下節能環保汽車推廣工作的通知》,決定從2013年10月1日起至2015年12月31日,繼續實施1.6升及以下節能環保汽車(乘用車)推廣政策,對購買符合條件節能汽車的消費者給予3000元補貼。截止2015年末,國家共實施了3個階段的汽車節能補貼,從每一輪政策的推出可以發現,國家對享受節能補貼的車型要求在逐年提高,推廣車輛要達到產品綜合燃料消耗量標準也由2011年的6.9L調整到2013年的5.9L,且需符合“國V”排放標準。

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

【其他文章推薦】

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

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

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

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

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

賓士傳將開發四款純電動車

世界級車商賓士(Mercedes-Benz)被報導正在開發全新的電動車平台,並將以此平台為基礎,推出四款純電動汽車。

ETToday引述外媒《Car Magazine》的報導,表示賓士正以MRA平台為基礎開發一款名為「EVA」的電動車平台,可供後續開發C-Class到S-Class尺碼的各式車款,最高能搭載400公斤的電池組。而在動力方面,後驅車型可能搭載一具402匹馬力的電動馬達,四驅車行可能還會再加上一具120匹馬力或者201匹馬力的馬達。主動懸載、扭力分配、動能回收等功能也將面面俱到。

該報導表示,賓士官方並未證實這項消息,但將在2018年推出C-Class與E-Class之間的電動轎車,並以此為基礎再行打造一款休旅車。此後還有S-Class和GLS等級的電動車款會問世。《Car Magazine》表示,賓士目標為每年銷售2萬輛電動車,入門車款售價為7萬英鎊起跳。

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

【其他文章推薦】

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

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

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

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

吉利:到2020年新能源汽車銷量將實現90%以上的占比

日前,吉利控股集團董事長李書福在接受《中國經營報》記者採訪時表示,以後我們開發的新產品基本是新能源汽車和智慧互聯汽車,傳統汽車就逐漸不生產了。

此話背後,實際就是吉利於近日提出的“藍色吉利行動”中的重要一環,到2020年,其新能源汽車銷量將實現90%以上的銷量占比。

具體來說,根據“藍色吉利行動”,吉利新能源將在技術上主打純電動、油電混動、插電式混合動力三種路線,並通過兩大平臺——FE(中高端)與PE(緊湊級)平臺來發展純電動車板塊。

從以上路徑上看,吉利與其他車企並無二致,但其公佈的“五大承諾”卻足以讓業內熱議——第一,提前全面實現2020年國家第四階段每百公里5.0L的企業平均燃油消耗限值;第二,實現消費者用傳統汽車的購買成本購買插電式混動汽車的夢想;第三,實現到2020年新能源汽車銷量占吉利整體銷量的90%以上;第四,在氫燃料及金屬燃料電池汽車研發方面取得實質性成果;第五,實現新能源技術,智慧化、輕量化技術在行業的領先地位。

雖然言之鑿鑿,但不得不說的是,90%以上的新能源銷量加上此前吉利發佈的“2020年實現120萬輛”的銷量目標,同年吉利新能源汽車銷量目標竟逾100萬輛。

對此,吉利控股集團總裁CEO安聰慧表示:“吉利制定這樣的目標並不是為了和其他企業進行對比,而是結合自身發展提出來的。”

據其介紹,在技術領域,吉利汽車將以與沃爾沃合作打造的CMA中高級車基礎模組架構為核心打造新能源車型,該方面的設計研發工作主要由吉利汽車歐洲研發中心承擔,該中心在瑞典哥德堡已有1200名工程師,中國杭州也有300名工程師,負責架構開發、上車體開發、核心部件開發開發,整車設計、工程製造及新技術的研發。CMA基礎模組架構可以實現電機+發動機等核心部件的批量生產。

此外,2015年初,吉利與新大洋機電集團成立合資公司並推出知豆電動車,加之此前其子公司上海華普國潤與康迪車業成立的合資公司,署名吉利旗下的新能源車型並不止吉利品牌。雖然,吉利在新能源領域的開疆破土頗有“借力而為”之感,但不論如何,2015年1~11月,在乘聯會統計的自主品牌新能源車銷量占比情況中,吉利節節攀升,的確實現了在自主品牌領域的市占率穩增,也正因如此,加之政策的多重鼓勵,吉利才許下到2020年實現新能源汽車逾百萬的戰略目標。

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

【其他文章推薦】

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

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

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

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

Deepin 下 使用 Rider 開發 .NET Core

目錄

Deepin 下 使用 Rider 開發 .NET Core

國產的 Deepin 不錯,安利一下。

Deepin 用了也有一兩年,也只是玩玩,沒用在開發上面。後來 Win10 不太清真了,就想着能不能到 Deepin下擼碼。要搞開發,首先少不了 IDE,VS2019 用不來,Vs Code 太複雜、麻煩,後來發現了 Rider 這個神器,可是 Rider 是英文界面,筆者的英文是渣渣的。結果在 Windows 下 使用 Rider 開發一段時間后, 已經熟悉了 Rider ,於是計劃後面遷移到 Deepin 下開發 .NET Core 。筆者裝了雙系統 Windows10 + Deepin 15。

安裝 Rider

Rider 的Linux 下載地址

下載壓縮包后,將壓縮包解壓,打開 bin 目錄,在目錄下打開終端,運行

sh rider.sh

或者直接點擊 rider.sh 文件,選擇執行即可。

之後會彈出安裝界面。

根據提示一步步安裝。

最後會要求輸入賬號密碼或者激活碼激活 Rider 。

我這個是高材生的福利~你們沒有的話就用 Github 開源項目免費申請使用,或者其他手段激活。

安裝完畢后,點擊 New Solution ,發現只能創建 .NET Frameork 的項目(Mono)。

先關閉 Rider ,接下來安裝 .NET Core

安裝 .NET Core SDK

有兩種安裝方法

  1. 自己下載二進制的 安裝包

  2. 使用軟件包形式安裝

    無論哪種方法,如果不把 SDK/Runtime 放到 /usr/share/dotnet 下,Rider 是無法識別的(默認路徑,可以進入Rider修改設置),下面兩種方法都是在 Linux 簡單二進制安裝 .NET Core SDK的方法。

sudo ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet -f
export DOTNET_ROOT=/usr/share/dotnet export 
PATH=$PATH:/usr/share/dotnet

推薦第一種方法,第二種方法的或,可以按照微軟的文檔自己試試。。。

安裝完畢后就是這個樣子。

如果要通過軟件包形式安裝,參考一下這裏 

體驗開發

想不到在 Deepin 下,Rider 竟然支持 Desktop Application(WPF)。

不過這不是重點,我又不會 WPF,先試一下 ASP.NET Core ,晚一點再看看 WPF。

運行的時候,報這個錯,是 Https 證書的問題,只需要任意位置打開終端,輸入下面的命令即可。

dotnet dev-certs https

不知道為什麼,瀏覽器打開 Blazor 應用一片空白。。。

換成 MVC 試試。

不知道為什麼 Blazor 打開會空白。不管了,試試 Desktop Application。

創建 Wpf 項目后,提示要安裝插件,然後退出重新打開。

不過最後重新打開項目還是報錯

Project 'WpfApp1' load finished with warnings
            The imported project "/usr/share/dotnet/sdk/3.0.100/Sdks/Microsoft.NET.Sdk.WindowsDesktop/targets/Microsoft.WinFX.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.  /usr/share/dotnet/sdk/3.0.100/Sdks/Microsoft.NET.Sdk.WindowsDesktop/targets/Microsoft.NET.Sdk.WindowsDesktop.targets at (26:3)
            Windows is required to build Windows desktop applications. at (59:5)

算了~就這樣好了,反正我又不會 WPF ~

本文是使用 Typora 寫的,很清真。

好好學習唄~

最後錄了個視頻玩,不知道說啥,看看內容界面就好~

打不開的話,請點擊 

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

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

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

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

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

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