測驗奇譚,BUG不見,
講解之前,我先說說我的教程和網上其他教程的區別:
1 我分享的是我在作業中高頻使用的場景,是精華內容;
很多人學習蟒蛇,不知道從何學起, 很多人學習尋找python,掌握了基本語法之后,不知道在哪里案例上手, 很多已經可能知道案例的人,卻不怎么去學習更多高深的知識, 這三類人,我給大家提供一個好的學習平臺,免費獲取視頻教程,電子書,以及課程的源代碼! QQ群:101677771 歡迎加入,一起討論學習
2 我分享的是學習方法,亦或說,是指明你該學哪些、該重點掌握哪些內容;
3 基于1和2,你可以按照我的教程學,也可以網上找視頻學,也可以看書學……你得明白,掌握學習方法比找學習資料重要得多,
前5期,我已經分享了python的基礎語法,如果你按照我的文章,一步一步練習,保準你對python代碼的語法特點、書寫方式有所了解,并能獨立的寫一些簡單的函式方法,甚至能嘗試開始自動化測驗的實踐(基于python語法),
當然,如果你想更進一步掌握python語法的特點,那接下來的幾篇文章一定不要錯過,
這一場,主講python的 生成器和匿名函式,
目的:掌握這兩個知識點的概念和使用,
生成器
01 什么是生成器?
記住兩個關鍵:
- 生成器是一種特殊的函式方法, 意味著它和函式(def)密不可分,
- 基于上一點, 只要函式中出現yield關鍵字,就是生成器函式 ,
初學的你,還是太難理解?
02 通俗的講解
你可以將生成器理解為一個盒子,你可以向這個盒子里隨意添加元素,當你需要的時候,再取出來用,
請看下面的例子:
# 普通函式
def func():
return 1
f = func()
print("函式回傳值:",f)
->函式回傳值:1
print("函式回傳值的型別:",type(f))
->函式回傳值的型別:<class 'int'>
# 生成器
def gen_func():
yield 1
yield 2
g = gen_func()
print("生成器物件:",g)
->生成器物件:<generator object gen_func at 0x00000189B8CFF7C8>
print("生成器物件的型別:",type(g))
->生成器物件的型別:<class 'generator'>
# 讀取生成器物件的值,因為生成器也是一個迭代器,實作了python的迭代協議(即實作了__iter__方法)
for i in g:
print("生成器物件的值:",i)
->生成器物件的值: 1
->生成器物件的值: 2
03 生成器到底有什么用?
作用:惰性求值(一邊回圈一邊計算的機制),節省性能
04 生成器的常見用途?
- 讀大檔案
- 網路爬蟲 scrapy 框架
- 協程
舉個例子:斐波那契數列(0,1,1,2,3,5...),列印斐波那契數列前50個元素
# 不使用生成器,會消耗大量記憶體
def fib(idx):
res=[]
n, a, b = 0, 0, 1
while n < idx:
res.append(b)
a, b = b, a+b
n += 1
return res
res = fib(100)
print(res)
# 使用生成器,可節約大量記憶體
def gen_fib(idx):
n, a, b = 0, 0, 1
while n < idx:
yield b
a, b = b, a+b
n += 1
for i in gen_fib(100):
print(i)
匿名函式
01 什么是匿名函式?
當:
- 函式實作比較簡單
- 函式不需要被多個地方呼叫
- 懶得給這個函式起名字
時,我們可以使用匿名函式,
初學的你,還是太難理解?
02 通俗的講解
你想實作一個求x的平方的函式,但是這個函式太簡單,不值得專門def定義,同時,你忘記了平方的英文如何拼寫,要是命名成 "pingfang",又顯得自己太low,于是乎,你可以不給這個函式起名字,還能實作它,這就是匿名函式lambda運算式,
比如:求一個數的平方
# 不用 lambda 運算式
def square(x):
return x * x
print(square(2))
# 使用 lambda 運算式
# 寫法:lambda 回傳值:計算運算式
s = lambda x: x * x
print(s(2))
一如既往,做個總結
01 如果你是初學者,可以先不掌握生成器和匿名函式,待學成python后,再行琢磨;
02 在實際作業中,生成器和匿名函式的使用頻次,相對較高,并且在面試中是高頻問點,
測驗奇譚,BUG不見,
大家好,我是譚叔,
這一場,主講python的 行程和執行緒 ,
目的:掌握初學必須的行程和執行緒知識,
行程和執行緒的區別和聯系
終于開始加深難度,來到行程和執行緒的知識點~
單就這兩個概念,就難倒過不少初學者——今天學了概念,明天就忘記;明天學了例子,又忘記了概念,
要理解行程和執行緒的聯系和區別,我舉個特簡單的例子:
你的電腦有兩個瀏覽器,一個谷歌瀏覽器,一個qq瀏覽器,
一個瀏覽器就是一個行程,
然后,你打開了谷歌瀏覽器,百度搜索了測驗奇譚,又新開一個標簽頁,打開譚叔的文章,如下圖所示:
你可以這樣理解—— 在同一個瀏覽器打開的兩個網頁就是兩個執行緒 , 如果我關閉了瀏覽器,這兩個執行緒也沒有了,
好了,當你有了概念后,我才好講兩者的區別和聯系,
行程
- 優點穩定性高 ,當程式崩潰后,不影響其他行程的使用,即谷歌瀏覽器崩潰后,qq瀏覽器還可以正常使用,
- 缺點創建行程的代價大 ,即當你開了各種各樣的瀏覽器后,你的電腦會特別卡,因為電腦記憶體和CPU有上限,
執行緒
- 優點多執行緒通常比多行程快一點,但優勢不大
- 缺點任何一個執行緒掛掉會造成整個行程崩潰,因為執行緒共享行程的記憶體(瀏覽器的例子不再適用,可以理解為綁在一條船上的螞蚱)
多行程
因為大多數小伙伴用的Windows作業系統,所以針對Unix/Linux的fork()呼叫拋開不談,
在python,一般使用multiprocessing實作多行程,
import os
from multiprocessing import Process
def run_proc(name):
print('開始執行子行程 %s (%s)…' % (name, os.getpid()))
# 子行程要執行的代碼
if __name__ == '__main__':
print('父行程 %s.' % os.getpid())
p = Process(target=run_proc, args=('test',)) # 創建一個Process實體
print('子行程即將開始.')
p.start() # 用start()方法啟動實體
p.join() # join()方法可以等待子行程結束后再繼續往下運行,通常用于行程間的同步
print('子行程結束.')
要細講嗎?
其實,我的備注寫得很全,你只需copy代碼下來執行一次,或者debug一次,就能明白,
執行緒池
如何理解?
即代碼可運行的行程數量,有個地方管控它,
from multiprocessing import Pool
import os
import time
import random
def long_time_task(name):
print('開始 task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s 執行花費 %0.2f 秒.' % (name, (end - start)))
if __name__ == '__main__':
print('父親行程 %s.' % os.getpid())
p = Pool(3)
# 因為Pool的默認大小是4,故task 0,1,2,3是立刻執行的,而task 4要等待前面某個task完成后才執行,但最多同時執行4個行程
# 由于Pool的默認大小是CPU的核數,如果你擁有8核CPU,要提交至少9個子行程才能看到等待效果
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('等待子行程結束...')
p.close()
# 對Pool物件呼叫join()方法會等待所有子行程執行完畢
# 呼叫join()之前必須先呼叫close(),呼叫close()之后就不能繼續添加新的Process了
p.join()
print('所有子行程已執行.')
以上,是必知必會的,
當然,最好的學習時機是:當你要用時,再來復盤學,效果最佳,
如果你學了,沒有使用場景,我建議緩一緩學或者作為知識儲備,
多執行緒
多執行緒有三點必須提前明確:
- 多任務需求可以由多行程完成,也可以由一個行程內的多執行緒完成
- 行程是由若干執行緒組成
- 一個行程至少有一個執行緒
Python的標準庫提供了兩個模塊:_thread和threading,_thread是低級模塊,我們一般使用高級模塊threading(對_thread進行過封裝),
啟動一個執行緒就是把一個函式傳入并創建Thread實體,然后呼叫start()開始執行,我們看一個簡單的例子:
import time
import threading
# 新執行緒執行的代碼
def loop():
# 由于任何行程默認就會啟動一個執行緒,我們把該執行緒稱為主執行緒,主執行緒又可以啟動新的執行緒,
# Python的threading模塊有個current_thread()函式,它永遠回傳當前執行緒的實體
print('執行緒ss %s 運行中…' % threading.current_thread().name)
n = 0
# 主執行緒實體的名字叫MainThread,子執行緒的名字在創建時指定,我們用LoopThread命名子執行緒,在列印輸出的時候顯示名字
while n < 5:
n = n + 1
print('執行緒ss %s >>> %s' % (threading.current_thread().name, n))
time.sleep(1)
print('執行緒ss %s 已結束.' % threading.current_thread().name)
print('執行緒 %s is 運行中…' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
'''
對于 join()方法而言,其另一個重要方面是其實它根本不需要呼叫,
一旦執行緒啟動,它們 就會一直執行,直到給定的函式完成后退出,
如果主執行緒還有其他事情要去做,而不是等待這些執行緒完成(例如其他處理或者等待新的客戶端請求),
就可以不呼叫 join(),join()方法只有在你需要等待執行緒完成的時候才是有用的
'''
print('執行緒 %s 已結束.' % threading.current_thread().name)
同樣,以上內容,是必知必會的,
并且,作業場景,我們一般會使用多執行緒處理問題,而非多行程,(注意:是一般)
至于行程間通信、執行緒鎖、GIL鎖、多執行緒變數、執行緒間通信、異步協程等知識,講起來比較復雜,也不是極簡教程的核心,你可以先自學,或者當你真正要使用它的時候再去看,再去學,
一如既往,做個總結
01 多執行緒、多行程,是必知必會的;
02 學習進度自己琢磨,既不能死磕,亦不能簡單跳過;
03 小伙伴比較關心,面試時會不會被問到,答:一般公司不會,so?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/412874.html
標籤:Python
上一篇:java中Random類的使用
