Appium+python自動化(四十一)-Appium自動化測試框架綜合實踐 – 即將落下帷幕(超詳解)

1.簡介

  今天我們緊接着上一篇繼續分享Appium自動化測試框架綜合實踐 – 代碼實現。到今天為止,大功即將告成;框架所需要的代碼實現都基本完成。

2.data數據封裝

2.1使用背景

在實際項目過程中,我們的數據可能是存儲在一個數據文件中,如txt,excel、csv文件類型。我們可以封裝一些方法來讀取文件中的數據來實現數據驅動。

2.2案例

將測試賬號存儲在account.csv文件,內容如下:

account.csv

hg2018

hg2018

hg2019

zxw2019

666

222

參考代碼

2.3enumerate()簡介

enumerate()是python的內置函數

  • enumerate在字典上是枚舉、列舉的意思
  • 對於一個可迭代的(iterable)/可遍歷的對象(如列表、字符串),enumerate將其組成一個索引序列,利用它可以同時獲得索引和值
  • enumerate多用於在for循環中得到計數。

2.4enumerate()使用

如果對一個列表,既要遍歷索引又要遍曆元素時,首先可以這樣寫:

參考代碼
list = ["這", "是", "一個", "測試","數據"]

for i in range(len(list)):

    print(i,list[i])

上述方法有些累贅,利用enumerate()會更加直接和優美:

參考代碼
list1 = ["這", "是", "一個", "測試","數據"]

for index, item in enumerate(list1):

        print(index,item)

3.數據讀取方法封裝

  數據讀取方法也屬於公共方法,這裏我們首先實現一下,然後將其封裝到裡邊即可。

3.1數據讀取方法實現的參考代碼

import csv


     def get_csv_data(csv_file,line):

        with open(csv_file, 'r', encoding='utf-8-sig') as file:

            reader=csv.reader(file)

            for index, row in enumerate(reader,1):

                if index == line:

                    return row

 

    csv_file='../data/account.csv'

    data=get_csv_data(csv_file,3)

    print(data)

3.2封裝

將其封裝在公共方法中,在其他地方用到的時候,直接導入調用即可。

4.utf-8與utf-8-sig兩種編碼格式的區別

UTF-8以字節為編碼單元,它的字節順序在所有系統中都是一樣的,沒有字節序的問題,也因此它實際上並不需要BOM(“ByteOrder Mark”)。但是UTF-8 with BOM即utf-8-sig需要提供BOM。

5.config文件配置

各種配置文件都放在這個目錄下。

5.1日誌文件配置 

主要是一些日誌信息的配置。

log.config

 參考代碼
[loggers]
keys=root,infoLogger

[logger_root]
level=DEBUG
handlers=consoleHandler,fileHandler

[logger_infoLogger]
handlers=consoleHandler,fileHandler
qualname=infoLogger
propagate=0

[handlers]
keys=consoleHandler,fileHandler

[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=form02
args=(sys.stdout,)

[handler_fileHandler]
class=FileHandler
level=INFO
formatter=form01
args=('../logs/runlog.log', 'a')

[formatters]
keys=form01,form02

[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s

[formatter_form02]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s

6.測試用例封裝

這裏宏哥舉例給小夥伴們演示:封裝註冊和登錄兩個測試用例。

6.1測試用例執行開始結束操作封裝

測試用例執行開始和結束的封裝,其他模塊用到直接導入,調用即可。

myunit.py

參考代碼
# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.註釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2019-11-20
@author: 北京-宏哥   QQ交流群:707699217
Project:Appium自動化測試框架綜合實踐 - 代碼實現
'''
# 3.導入模塊
import unittest
from kyb_testProject.common.desired_caps import appium_desired
import logging
from time import sleep

class StartEnd(unittest.TestCase):
    def setUp(self):
        logging.info('=====setUp====')
        self.driver=appium_desired()

    def tearDown(self):
        logging.info('====tearDown====')
        sleep(5)
        self.driver.close_app()

6.2註冊用例

開始註冊用例代碼邏輯的實現。

test_register.py

參考代碼
# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.註釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2019-11-20
@author: 北京-宏哥   QQ交流群:707699217
Project:Appium自動化測試框架綜合實踐 - 代碼實現
'''
# 3.導入模塊
from kyb_testProject.common.myunit import StartEnd
from kyb_testProject.businessView.registerView import RegisterView
import logging,random,unittest

class RegisterTest(StartEnd):
    def test_user_register(self):
        logging.info('======test_user_register======')
        r=RegisterView(self.driver)

        username = 'bjhg2019' + 'fly' + str(random.randint(1000, 9000))
        password = 'bjhg2020' + str(random.randint(1000, 9000))
        email = 'bjhg' + str(random.randint(1000, 9000)) + '@163.com'

        self.assertTrue(r.register_action(username,password,email))

if __name__ == '__main__':
    unittest.main()

6.3登錄用例

開始登錄用例代碼邏輯的實現。

test_login.py

參考代碼
# coding=utf-8
# 1.先設置編碼,utf-8可支持中英文,如上,一般放在第一行

# 2.註釋:包括記錄創建時間,創建人,項目名稱。
'''
Created on 2019-11-13
@author: 北京-宏哥   QQ交流群:707699217
Project:Appium自動化測試框架綜合實踐 - 代碼實現
'''
# 3.導入模塊
from kyb_testProject.common.myunit import StartEnd
from kyb_testProject.businessView.loginView import LoginView
import unittest
import logging

class TestLogin(StartEnd):
    csv_file='../data/account.csv'

    @unittest.skip('test_login_zxw2018')
    def test_login_zxw2018(self):
        logging.info('======test_login_zxw2018=====')
        l=LoginView(self.driver)
        data=l.get_csv_data(self.csv_file,2)

        l.login_action(data[0],data[1])
        self.assertTrue(l.check_loginStatus())

    # @unittest.skip('skip test_login_zxw2017')
    def test_login_zxw2017(self):
        logging.info('======test_login_zxw2017=====')
        l=LoginView(self.driver)
        data = l.get_csv_data(self.csv_file, 1)

        l.login_action(data[0], data[1])
        self.assertTrue(l.check_loginStatus())

    @unittest.skip('test_login_error')
    def test_login_error(self):
        logging.info('======test_login_error=====')
        l = LoginView(self.driver)
        data = l.get_csv_data(self.csv_file, 3)

        l.login_action(data[0], data[1])
        self.assertTrue(l.check_loginStatus(),msg='login fail!')

if __name__ == '__main__':
    unittest.main()

7.小結

到此,Appium自動化測試框架就差下一篇就全部完成了,聰明的你都懂了嗎???嘿嘿!慢慢地來吧。

下節預告

下一篇,講解執行測試用例,生成測試報告,以及自動化平台,請關注宏哥,敬請期待!!!

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

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

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

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

※台灣海運大陸貨務運送流程

※兩岸物流進出口一站式服務

Toyota將在中國成立PHEV產線

日本豐田(Toyota)日前於北京發表會上表示,計畫在2018年時開始在中國市場推出PHEV(插電式油電混和車)產品,同時計畫轉移部份產能到中國。

在Toyota表示將在中國推出PHEV之際,因應在地生產的方針,Toyota也首度規劃在日本以外的國家生產PHEV電動車。去年秋天,Toyota已於中國發售Corolla、Levin兩款中國生產的混和車,未來將會推出這兩款車款的PHEV版本。

Toyota表示,2018年左右,會有更多品牌陸續在中國推出PHEV或純電動車,因此需搶先布局中國的相關產線。此外,在中國生產的車款將以中國市場為主,且以組裝為中國產線的主要業務。核心技術與配件則仍留在日本國內。

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

買電動車送補貼金?傳德國財政部提12億歐元獎勵方案

德國電動車銷售積弱不振,據傳財政部已提出總額12億歐元(相當於13.5億美元)的補貼法案,希望為電動車市重新注入活力,而所需費用將由政府及車商聯手買單。

華爾街日報25日引述未具名消息人士報導,德國政府高層和汽車產業代表即將在26日與德國總理梅克爾會面,討論刺激電動車銷售量的獎勵措施,另外也會考慮直接由政府出資、在全國建設充電站。

根據財政部提出的建議,在2016年至2018年夏季期間,購買電動車的民眾可獲得政府與車商補貼5,000歐元,購買油電混合動力車的民眾則可獲得3,000歐元的補助,在此之後補貼金額會分別下降至3,000歐元(電動車)、2,000歐元(油電混合動力車)。

消息顯示,售價高於60,000歐元的電動車不在補助範圍之內,以免獎勵措施淪為補貼富人買車的工具。另外,這個方案將遵循先買先補貼的原則,12億歐元的補助款用罄之後將不再補款。財政部也提議提供3億歐元的額外補貼,為電動車設立充電站。

Thomson Reuters報導,梅克爾甫於4月12日呼籲汽車製造商開出願望清單。梅克爾表示,官方將盡快清除法律障礙、讓他們可以在德國測試無人駕駛車。她透露,德國執政聯盟將在5月底開會討論自駕車法令規範。德國財長Wolfgang Schaeuble上個月說,官方將設法協助電動車開發、但可能無法讓所有車商感到滿意。車界領袖呼籲,德國若想維持全球領導地位、政府就得想辦法提振電動車買氣。

蘋果在德國的電動車開發案似乎正進行的如火如荼。AppleInsider 4月18日引述法蘭克福廣訊報(Frankfurter Allgemeine Zeitung)報導,蘋果已在柏林設立秘密開發實驗室,目前在當地擁有15-20名工程、軟體、硬體、行銷背景的德國汽車業頂尖人才。報導指出,蘋果進軍汽車業的第一款產品將是電動車、但初期不具備自駕功能。

(本文內容由授權提供)

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

【其他文章推薦】

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

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

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

※台灣海運大陸貨務運送流程

※兩岸物流進出口一站式服務

通過javascript 執行環境理解她

古往今來最難的學的武功(javascript)算其一。

欲練此功必先自宮,願少俠習的此功,笑傲江湖。

你將了解

  • 執行棧(Execution stack)
  • 執行上下文(Execution Context)
  • 作用域鏈(scope chains)
  • 變量提升(hoisting)
  • 閉包(closures)
  • this 綁定

執行棧

又叫調用棧,具有 LIFO(last in first out 後進先出)結構,用於存儲在代碼執行期間創建的所有執行上下文。

當 JavaScript 引擎首次讀取你的腳本時,它會創建一個全局執行上下文並將其推入當前的執行棧。每當發生一個函數調用,引擎都會為該函數創建一個新的執行上下文並將其推到當前執行棧的頂端。
引擎會運行執行上下文在執行棧頂端的函數,當此函數運行完成后,其對應的執行上下文將會從執行棧中彈出,上下文控制權將移到當前執行棧的下一個執行上下文。

我們通過下面的示例來說明一下

function one() {
  console.log('one')
  two()
}
function two() {
  console.log('two')
}
one()

當程序(代碼)開始執行時 javscript 引擎創建 GobalExecutionContext (全局執行上下文)推入當前的執行棧,此時 GobalExecutionContext 處於棧頂會立刻執行全局執行上下文 然後遇到 one() 引擎都會為該函數創建一個新的執行上下文 oneFunctionExecutionContext 並將其推到當前執行棧的頂端並執行,然後遇到two() twoFunctionExecutionContext 入棧並執行至出棧,回到 oneFunctionExecutionContext 繼續執行至出棧 ,最後剩餘一個 GobalExecutionContext 它會在程序關閉的時候出棧。

然後調用棧如下圖:

如果是這樣的代碼

function foo() {
  foo()
}
foo()

如下

當一個遞歸沒有結束點的時候就會出現棧溢出

什麼是執行上下文

了解 JavaScript 的執行上下文,有助於你理解更高級的內容比如變量提升、作用域鏈和閉包。既然如此,那到底什麼是“執行上下文”呢?

執行上下文是當前 JavaScript 代碼被解析和執行時所在環境的抽象概念。

Javascript 中代碼的執行上下文分為以下三種:

  1. 全局執行上下文(Global Execution Context)- 這個是默認的代碼運行環境,一旦代碼被載入,引擎最先進入的就是這個環境。
  2. 函數執行上下文(Function Execution Context) – 當執行一個函數時,運行函數體中的代碼。
  3. Eval – 在 Eval 函數內運行的代碼。

javascript 是一個單線程語言,這意味着在瀏覽器中同時只能做一件事情。當 javascript 解釋器初始執行代碼,它首先默認進入全局上下文。每次調用一個函數將會創建一個新的執行上下文。

javascript執行棧中不同執行上下文之間的詞法環境有一種關聯關係,從棧頂到棧底(從局部直到全局),這種關係被叫做作用域鏈。

簡單的說,每次你試圖訪問函數執行上下文中的變量時,進程總是從自己上下文環境中開始查找。如果在自己的上下文中沒發現要查找的變量,繼續搜索下一層上下文。它將檢查執行棧中每一個執行上下文環境,尋找和變量名稱匹配的值,直到找到為止,如果到全局都沒有則拋出錯誤。

執行上下文的創建過程

我們現在已經知道,每當調用一個函數時,一個新的執行上下文就會被創建出來。然而,在 javascript 引擎內部,這個上下文的創建過程具體分為兩個階段:

創建階段 > 執行階段

創建階段

執行上下文在創建階段創建。在創建階段發生以下事情:

  1. LexicalEnvironment 組件已創建。
  2. VariableEnvironment 組件已創建。

因此,執行上下文可以在概念上表示如下:

ExecutionContext = {
  LexicalEnvironment = <詞法環境>,
  VariableEnvironment = <變量環境>,
}

詞法環境(Lexical Environment)

文檔將詞法環境定義為:

詞法環境是一種規範類型,基於 ECMAScript 代碼的詞法嵌套結構來定義標識符與特定變量和函數的關聯關係。詞法環境由環境記錄(environment record)和可能為空引用(null)的外部詞法環境組成。

簡而言之,詞法環境是一個包含標識符變量映射的結構。(這裏的標識符表示變量/函數的名稱,變量是對實際對象【包括函數類型對象】或原始值的引用)

詞法環境有兩種類型

  • 全局環境(在全局執行上下文中)是一個沒有外部環境的詞法環境。全局環境的外部環境引用為 null。它擁有一個全局對象(window 對象)及其關聯的方法和屬性(例如數組方法)以及任何用戶自定義的全局變量,this 的值指向這個全局對象。
  • 函數環境,用戶在函數中定義的變量被存儲在環境記錄中。對外部環境的引用可以是全局環境,也可以是包含內部函數的外部函數環境。

每個詞彙環境都有三個組成部分:

1)環境記錄(environment record)

2)對外部環境的引用(outer)

3) 綁定 this

環境記錄 同樣有兩種類型(如下所示):

  • 聲明性環境記錄 存儲變量、函數和參數。一個函數環境包含聲明性環境記錄。
  • 對象環境記錄 用於定義在全局執行上下文中出現的變量和函數的關聯。全局環境包含對象環境記錄

抽象地說,詞法環境在偽代碼中看起來像這樣:

詞法環境和環境記錄值是純粹的規範機制,ECMAScript 程序不能直接訪問或操縱這些值。

GlobalExectionContext = {
  // 詞法環境
  LexicalEnvironment:{
    // 功能環境記錄
    EnvironmentRecord:{
      Type:"Object",
      // Identifier bindings go here
     }
    outer:<null>,
    this:<global object>
  }
}
FunctionExectionContext = {
  LexicalEnvironment:{
    EnvironmentRecord:{
      Type:"Declarative",
      // Identifier bindings go here
     }
    outer:<Global or outer function environment reference>,
    this:<取決於函數的調用方式>
  }
}

變量環境:

它也是一個詞法環境,其 EnvironmentRecord 包含了由 VariableStatements 在此執行上下文創建的綁定。
如上所述,變量環境也是一個詞法環境,因此它具有上面定義的詞法環境的所有屬性。
在 ES6 中,LexicalEnvironment 組件和 VariableEnvironment 組件的區別在於前者用於存儲函數聲明和變量( let 和 const )綁定,而後者僅用於存儲變量( var )綁定。
讓我們結合一些代碼示例來理解上述概念:

let a = 20
const b = 30
var c

function multiply(e, f) {
  var g = 20
  return e * f * g
}

c = multiply(20, 30)

執行上下文如下所示:

GlobalExectionContext = {
  LexicalEnvironment:{
    EnvironmentRecord:{
      Type:"Object",
      // Identifier bindings go here
      a:<uninitialized>,
      b:<uninitialized>,
      multiply:<func>
    },
    outer:<null>,
    ThisBinding:<Global Object>
  },
  VariableEnvironment:{
    EnvironmentRecord:{
      Type:"Object",
      // Identifier bindings go here
      c:undefined,
    }
    outer:<null>,
    ThisBinding:<Global Object>
  }
}

在執行階段,完成變量賦值。因此,在執行階段,全局執行上下文將看起來像這樣。

// 執行
GlobalExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      a: 20,
      b: 30,
      multiply: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

當 multiply(20, 30)遇到函數調用時,會創建一個新的函數執行上下文來執行函數代碼。因此,在創建階段,函數執行上下文將如下所示:

// multiply 創建
FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

在此之後,執行上下文將執行執行階段,這意味着完成了對函數內部變量的賦值。因此,在執行階段,函數執行上下文將如下所示:

// multiply 執行
FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      g: 20
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

函數完成后,返回的值賦值給c。因此,全局詞法環境得到了更新。之後,全局代碼完成,程序結束。

注: 在執行階段,如果 Javascript 引擎在源代碼中聲明的實際位置找不到 let 變量的值,那麼將為其分配 undefined 值。

變量提升

在網上一直看到這樣的總結: 在函數中聲明的變量以及函數,其作用域提升到函數頂部,換句話說,就是一進入函數體,就可以訪問到其中聲明的變量以及函數。這是對的,但是知道其中的緣由嗎?相信你通過上述的解釋應該也有所明白了。不過在這邊再分析一下。

你可能已經注意到了在創建階段 let 和 const 定義的變量沒有任何與之關聯的值,但 var 定義的變量設置為 undefined。
這是因為在創建階段,代碼會被掃描並解析變量和函數聲明,其中函數聲明存儲在環境中,而變量會被設置為 undefined(在 var 聲明變量的情況下)或保持未初始化(在 let 和const 聲明變量的情況下)。
這就是為什麼你可以在聲明之前訪問var 定義的變量(儘管是 undefined ),但如果在聲明之前訪問let 和const 定義的變量就會提示引用錯誤的原因。
這就是我們所謂的變量提升。

思考題:

console.log('step1:',a)
var a = 'artiely'
console.log('step2:',a)
function bar (a){
  console.log('step3:',a)
  a = 'TJ'
  console.log('step4:',a)
  function a(){
  }
}
bar(a)
console.log('step5:',a)

對外部環境的引用

上面代碼如果我們改用調用方式如下:

let a = 20
const b = 30
var c

function multiply() {
  var g = 20
  return a * b * g
}

c = multiply()

其實你會發現結果是一樣的
但是 multiply 的執行上下文卻發生一些變化

// 創建
FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      Arguments: { length: 0},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}
// 執行
FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      Arguments: { length: 0},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: 20
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

multiply() 執行的時候會直接在 outer: <GlobalLexicalEnvironment>,中查找a,b

對外部環境的引用意味着它可以訪問其外部詞法環境。這意味着如果在當前詞法環境中找不到它們,JavaScript 引擎可以在外部環境中查找變量。這就是之前說的 作用域鏈

閉包

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

這是我認為對閉包最合理的解釋了,就看你怎麼理解閉包的機制了。
其實閉包與作用域鏈有着密切的關係。

首先我們來看看什麼樣的代碼會產生閉包。

function foo() {
  var name = 'artiely'
  function bar() {
    console.log(`hello `)
  }
  bar()
}
foo()

以上代碼是有閉包嗎?沒有~

function foo() {
  var name = 'artiely'
  function bar() {
    console.log(`hello ${name}`)
  }
  bar()
}
foo()

我們只做了微小的調整,現在就有閉包了,我們只是在bar中加入了name得引用
上面的代碼還可以寫成這樣

// 或者
function foo() {
  var name = 'artiely'
  return function bar() {
    console.log(`hello ${name}`)
  }
}
foo()()

對於閉包的形成我進行了如下的幾點歸納

  1. A 函數內必須有 B 函數的聲明;
  2. B 函數必須引用 A 函數的變量;
  3. B 函數被調用(當然前提是 A 函數被調用)

以上 3 點缺一不可

我們來分析一下上面代碼的執行上下文

// 創建
fooFunctionExectionContext = {
LexicalEnvironment: {
  EnvironmentRecord: {
    Type: "Declarative",
    Arguments: { length: 0},
    bar: < func >,
  },
  outer: <GlobalLexicalEnvironment>,
  ThisBinding: <Global Object or undefined>,
},
VariableEnvironment: {
  EnvironmentRecord: {
    Type: "Declarative",
    name: undefined
  },
  outer: <GlobalLexicalEnvironment>,
  ThisBinding: <Global Object or undefined>
  }
}
// 執行 略
// 創建
barFunctionExectionContext = {
LexicalEnvironment: {
  EnvironmentRecord: {
    Type: "Declarative",
    Arguments: { length: 0},
  },
  outer: <fooLexicalEnvironment>,
  ThisBinding: <Global Object or undefined>,
},
VariableEnvironment: {
  EnvironmentRecord: {
    Type: "Declarative",
  },
  outer: <fooLexicalEnvironment>,
  ThisBinding: <Global Object or undefined>
  }
}
// 執行 略

這裏因為bar的創建存在着對fooLexicalEnvironment里變量的引用,雖然foo可能執行已結束但變量不會被回收。這種機制被叫做閉包

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

我們結合上面例子重新分解一下這句話

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

但是從chrome的理解,閉包並沒有包含所能訪問的所有局部變量,僅僅包含所被引用的變量。

this 綁定

在全局執行上下文中,值是 this 指全局對象。(在瀏覽器中,this 指的是 Window 對象)。

在函數執行上下文中,值 this 取決於函數的調用方式。如果它由對象引用調用,則將值 this 設置為該對象,否則,將值 this 設置為全局對象或 undefined(在嚴格模式下)。例如:

let person = {
  name: 'peter',
  birthYear: 1994,
  calcAge: function() {
    console.log(2018 - this.birthYear)
  }
}

person.calcAge()
// 'this' 指向 'person', 因為 'calcAge' 是被 'person' 對象引用調用的。

let calculateAge = person.calcAge
calculateAge()
// 'this' 指向全局 window 對象,因為沒有給出任何對象引用

注意所有的()()自調用的函數 this 都是指向Global Object的既瀏覽器中的window

最後

如果本文對你有幫助或覺得不錯請幫忙點贊,如有疑問請留言。

其他參考:

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

ASP.NET Core 3.0 gRPC 身份認證和授權

一.開頭聊騷

本文算是對於 ASP.NET Core 3.0 gRPC 研究性學習的最後一篇了,以後在實際使用中,可能會發一些經驗之文。本文主要講 ASP.NET Core 本身的認證授權和gRPC接入,認證方式採用目前主流的 JWT 結合 IdentityServer4。

二.服務端配置

我們首先需要在服務端配置認證和授權。gRPC基於此文的Demo來開始: ,IdentityServer 基於此文Demo: 。

配置

1.首先啟動 IdentityServer4 地址為:

2.為gRPC項目安裝Jwt組件:Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 3.0.0

3.為gRPC項目配置認證和授權服務

在 Startup 類的 ConfigureServices 方法中,配置如下代碼

services.AddAuthorization(options =>
{
    options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
    {
        policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
        policy.RequireClaim("sub");
    });
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "http://localhost:5000";
        options.RequireHttpsMetadata = false;
        options.Audience = "grpc1";
    });

4.啟用認證授權中間件

在 Startup 類的 Configure 方法中,配置如下代碼

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

請務必注意中間件順序

5.為gRPC服務啟用授權

我們在 LuCatService 的 SuckingCat 方法上,加上 [Authorize]特性,就和在MVC中一樣。

測試

運行客戶端調用服務端來進行測試,發現服務端返回了授權失敗,客戶端同樣獲得了錯誤。這證明我們的服務端配置是沒有問題的

三.客戶端配置

配置

客戶端首先需要從 IdentityServer 申請 Token,然後在調用 gRPC 服務時傳遞過去,這和 HTTP Api 調用一樣。

1.客戶端項目安裝組件 IdentityModel 獲得基於 HttpClient 的和 IdentityServer 的交互的封裝。

2.獲取Token

// discover endpoints from metadata
var client = new HttpClient();

var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
if (disco.IsError)
{
    Console.WriteLine(disco.Error);
    return;
}

// request token
var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
    Address = disco.TokenEndpoint,
    ClientId = "ro.client",
    ClientSecret = "secret",

    UserName = "alice",
    Password = "password",
    Scope = "grpc1"
});

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");

3.為 gRPC 客戶端請求設置 Token

和 HTTP Api 調用一樣,gRPC也是放在頭部的

var headers = new Metadata {{"Authorization", $"Bearer {tokenResponse.Json["access_token"]}"}};

var catClient = new LuCat.LuCatClient(channel);
var catReply = await catClient.SuckingCatAsync(new Empty(), headers);

主要就是在調用 SuckingCatAsync方法時,傳入了header。

測試

可以看到成功的進行了調用。

四.結束

本文所用代碼地址:

gRPC in Asp.Net Core :

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

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

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

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

※台灣海運大陸貨務運送流程

※兩岸物流進出口一站式服務

串聯鈣鈦礦與 CIGS,新型薄膜太陽能轉換效率創新高達 24.6%

摘錄自2018年9月27日科技新報報導

繼月初加州大學洛杉磯分校帶來轉換效率達 22.4% 的鈣鈦礦─銅銦鎵硒(CIGS)太陽能電池,近期比利時歐洲跨校際微電子研究中心(IMEC)更進一步、將轉換效率突破至 24.6%,再一次創下新紀錄。

團隊採用 EnergyVille 與歐洲薄膜太陽能研究聯盟 Solliance 合作研發的鈣鈦礦、德國巴登符騰堡太陽能和氫能源研究中心(ZSW)面積僅 0.5 平方公分大小的 CIGS 太陽能,並透過添加光學耦合層與最佳化透明電極,提升鈣鈦礦對近紅外光的透光率。

除此之外,也改善鈣鈦礦 1.72eV 寬能隙,進一步提高鈣鈦礦─CIGS 太陽能轉換效率。ZSW 太陽能部門執行長 Michael Powalla 表示,目前已成功打造鈣鈦礦─CIGS 串聯太陽能原型,也提出了雙端子型串聯太陽能解決方案,未來則致力於將轉換效率提升至 30% 以上與打造更大的太陽能模組,盼該技術可助建築整合太陽能系統一臂之力。

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

奧地利一名果農因違法噴灑殺蟲劑,隸屬鄰近2個養蜂人超過50個蜂群因此死亡

奧地利一名果農因違法噴灑殺蟲劑,隸屬鄰近2個養蜂人超過50個蜂群因此死亡。26日奧地利克拉根福法院(Klagenfurt)以「蓄意危害環境」,判處果農1年有期徒刑,至少需服刑4個月才可假釋,以及賠償超過2萬歐元(2萬3500美元)。

這名47歲果農針對他位於奧地利卡林西亞省(Carinthia)拉萬特地區(Lavanttal)的果樹噴灑藥效強大的殺蟲劑陶斯松(chlorpyrifos),當時果樹的花仍會吸引蜜蜂前去。法院指出,以他的經驗和訓練他人的角色,足以證明他知道自身行為會帶來何種後果。

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

【其他文章推薦】

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

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

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

※台灣海運大陸貨務運送流程

※兩岸物流進出口一站式服務

中國首條電動汽車無線充電車道建成

早在2012年,南方電網廣西電力科學研究院29歲的祝文姬博士和年輕的科研團隊就開始了“面向智慧電網的無線電能傳輸關鍵技術”專案研究,踏上了“電動汽車無線充電供電技術”的探索之路。經過4年時間的科研試驗,今年初,「面向智慧電網的無線電能傳輸關鍵技術研究」項目驗收完成,科研人員開發了無線電能傳輸系統工程設計平臺,研製了駐停式電動汽車無線充電裝置,成功建成了中國國內第一條電動汽車無線供電小型試驗車道,打通了電動汽車充電的「最後一哩」。

作為該專案技術負責人,祝文姬博士說:「以後大家可以一邊開車一邊充電,甚至電動汽車沒有車載電池也能解決電源的問題。」邊走邊充,電動汽車開啟了無線供電的美好時代。

電動汽車無線供電車道可在固定行駛的公車路線、高速路、景區道路上推廣使用。祝文姬說:「無線供電車道類似於加油站,當電動汽車電量不足時,就可以駛入鋪設有無線供電系統的車道上,邊走邊充電,而且全過程不需要駕駛者下車操作。」

對於安全問題,祝文姬表示,電能傳輸過程中沒有導線的直接接觸,不存在電力安全隱患;至於電磁輻射,在系統設計之初就進行了考慮,經過協力廠商檢測機構測試後不但滿足國際輻射標準,還比標準低一半,不會危害駕駛人身體健康。

祝文姬稱,當前的電動汽車主要採用傳導充電方式。這種帶「尾巴」的充電方式需要使用充電電纜連線充電機和電動汽車。而擺脫了充電「尾巴」束縛的無線充電技術,不僅可以通過在車庫、停車場、公車停靠站等車輛停放處安裝駐停式電動汽車無線充電裝置,實現電動汽車停靠過程中的無線充電;還可以通過系統隨時遠端調節充電時長、即時監控車輛狀態,實現充滿電後自動斷電。

只要把車停到指定區域,不需要任何線纜就可以直接充電

最令電動汽車消費者欣慰的是,祝文姬團隊研發的電動汽車無線供電車道「不挑剔、不嬌氣」,任何品牌的電動汽車都可以使用,只需加裝無線接收裝置。而且充電時間大大減少,以總電池容量為24kWh的電動汽車為例,如果以30kW的功率進行充電,不到1小時即可充滿。

專案研究過程中並非一帆風順。2013年,在專案原計劃即將結題的時間點,祝文姬和她的科研團隊發現,電能轉換效率雖然比立項前的65%有顯著提升,但是仍然還有潛力可挖。當時1度電從電網傳輸到汽車上,除掉一些不可避免的損耗,汽車能接收到75%。本著對科研負責的態度,祝文姬申請將課題延遲2年結題。科研人員最終將電能轉換效率成功提升至85%,成功拿下電動汽車無線供電技術,並且達到了中國乃至世界先進水準。
 

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

【其他文章推薦】

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

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

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

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

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

※試算大陸海運運費!

特斯拉 Model 3 大賣,電動車朝向榮景仍逢瓶頸?

電動車大廠特斯拉(Tesla)新款房車 Model 3 的預購量超出預期,市場上開始有許多分析師發言,有的說電動車即將取代傳統的汽車;有人甚至認為應該忘掉正面臨創新瓶頸的 Apple 執行長 Tim Cook,將目光移向 Tesla 創辦人 Elon Musk,稱他是偉大夢想及實踐家,其能力傲視全球的企業家,然而事實真是如此嗎?   電動車大廠特斯拉(Tesla)新款房車 Model 3 於 2016 年 3 月展開全球預售,售價 3.5 萬美元(約新台幣 110 萬元),買主只需要預付 1,000 美元(約新台幣 3 萬元)就可以訂車,此舉立刻引起市場震撼,吸引大批車迷排隊預購,光是在一天內便湧入 11 萬筆訂單,首周預購就超過 32 萬筆。  
暗藏玄機的預購書   仔細看看 Tesla 的預購合約書(其實這算不上合約書只是預購同意書而已),就可以看出到底為什麼大家會一窩蜂的搶訂。Tesla 的預購條件很簡單,任何人想要訂購 Model 3,只需要支付 1,000 美元的訂金,而且任何時間如果後悔都可以全部退還,換句話說,對消費者而言沒有任何風險;同樣的,Tesla 在文件裡也沒有寫明交車時間,檯面上說 2017 年底是「預定」交車時間,但如果交不出來或延後到 2018 甚至 2020 年,也沒有任何罰則。   放眼望去,哪家車廠會訂出這種購車合約?這樣的操作 Tesla 的目的為何?   Tesla 成立於 2003 年,到現在已經超過 12 年了,它是第一家把電動車成功推到全球市場的公司,讓電動車與高級車畫上等號,吸引到高收入客戶。Tesla 帶給人們對於未來汽車的夢想,進而推升了它的高股價,甚至比大部分賺錢的公司還要高出十幾、二十倍。美國汽車在 2015 年銷售創下歷來最佳紀錄,但福特(Ford)和通用(GM)等汽車業者股票卻大跌,股價本益比僅 5~7 倍,而 Tesla 卻能在持續虧損下,過去 3 年漲了將近 400%,比標普 500 指數與其他傳統車商要好得多。   2013 年 Tesla 進軍中國,希望拿下繼美國之後第二個龐大的電動車市場,甚至 Musk 曾揚言「中國市場很快就超越美國成為 Tesla 電動車的第一大市場」。但是 Tesla 一直無法突破瓶頸,2015 第三季結束的交車總量只有 3,025 輛,不到全球交付量 50,580 輛的十分之一。目前看起來 Tesla 要搶下中國市場,還有一段很漫長的路要走,除了中國政策的問題,無補貼、高關稅、被排除在國家標準之外,各國車廠也紛紛摩拳擦掌,準備搶食中國電動車的市場大餅。   長期的虧損也讓華爾街的分析師對 Musk 的耐心慢慢消磨殆盡,除了進軍中國沒有交出漂亮的成績單,Tesla 還是延遲交貨的慣犯,從首款電動車 Roadster、次代 Model S 到電動休旅車 Model X,從未準時交貨,Model X 甚至還延遲超過一年半。  
先求資金到位以利發展   雖然 Model 3 被定位成平價車款,它的設計沒有其他現有車款 Model S 與 Model X 複雜,但是能不能準時交貨並不是 Tesla 說了算,還是得仰賴後端生產零件的供應商是否如期交貨。Tesla 也預見可能發生的狀況,已先幫自己找替代方案,在加州費利蒙〈Fremont〉的生產工廠自行製造所需零件。   另外電池材料來源與價格,也是必須考量的因素。電動車使用鋰電池做為動力來源,除了電池本身必須非常嚴謹安全,當需求量大增時也會推升鋰材料的價格,因此未必能夠因為數量大幅成長而使價格大幅下降。2015 年第四季開始,就發生鋰電池正極材料所需的碳酸鋰缺貨,導致鋰電池廠商無法擴產,碳酸鋰每噸的市場價格也從 2013 年 9 月的 5 萬人民幣上漲到 12 萬人民幣。Model 3 都還沒做出來碳酸鋰價格就開始上漲了!   大量的電動車充電需求也代表電力基礎建設必須更新,這也不是短時間內可以做到的事,而 Tesla 垂涎欲滴的中國市場,雖然計劃擴建充電站,卻只支援中國國內的電動車品牌。超級充電站不相容、充電難的問題將進一步加劇 Tesla 的困境。   Tesla 可以在一周內拿到超過 30 萬的消費者預購同意書,並不代表真的能做到這麼多生意,連 Musk 都對 2017 年是否能順利上市不太有信心,他在發表會上說「Model 3 不太可能如期交車」。而當 2017 年時間一到,如果交不出令人滿意的 Model 3,或是首購的客戶有了不好的評價,到時候退訂的浪潮也會很兇猛的。   因此 Tesla「不訂出逾期的賠償條款」,對消費者和他們而言可謂雙贏策略。對消費者來說沒有任何風險,還可以過過 Tesla 車主的癮,於是消費者瘋狂訂購;對 Tesla 來說,可以向華爾街的分析師與市場上的投資人證明 Tesla 的潛在客戶非常龐大,有利於向資本市場募資吸金,等於是先拿到了訂單,再回頭過來向市場募資,一箭雙鵰。  
交車不順恐不利後續發展   而 2017 年是否真的能交車呢?是否真的能賣到 3.5 萬美元這麼低的價格?那是以後的事了,只要資金到位,未來要怎麼做都好說;缺少了資金和市場信心,別談以後了,Tesla 可能就要面臨後勢不振的壓力了。   Musk 在資本市場上為投資人,也為新創公司建立一個遠大的夢想並沒有什麼不對,而且手法高明了許多,但 Musk 真的能把 Cook 比下嗎?蘋果一直以來都是腳踏實地在創新,東西真的做得好賣得好,而賺大錢富可敵國才讓股票大漲的,當然做得再好的產品也會遭遇瓶頸,但是這畢竟靠的是腳踏實地的「本益比」,而不是虛幻不實的「本夢比」。   在商場上投機的確是會成功的,有時候成功的機率還不低,但是如果我們過度推崇投機,把投機說成是偉大夢想及實踐能力傲視全球,那對腳踏實地在創新的 Steven Jobs 和 Cook 也太不公平了!   (首圖來源: CC BY 2.0)   (本文授權轉載自《》─〈〉)

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

【其他文章推薦】

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

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

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

※台灣海運大陸貨務運送流程

※兩岸物流進出口一站式服務

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  ?

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

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

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

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

※試算大陸海運運費!