Python 高級(jí) 7

迭代、迭代器肃拜、生成器痴腌、協(xié)程、yield燃领、greenlet士聪、gevent、進(jìn)程線程協(xié)程對(duì)比猛蔽、gevent多任務(wù)圖片下載

1.迭代

<1>迭代的概念

使用for循環(huán)遍歷取值的過(guò)程叫做迭代剥悟,比如:使用for循環(huán)遍歷列表獲取值的過(guò)程

for value in [2, 3, 4]:

print(value)

<2>可迭代對(duì)象

使用for循環(huán)遍歷取值的對(duì)象叫做可迭代對(duì)象, 比如:列表、元組、字典懦胞、集合、range凉泄、字符串

<3>判斷對(duì)象是否是可迭代對(duì)象

先導(dǎo)入collections包中的Iterable類

isinstance的使用

isinstance(o, t), object type

isinstance(對(duì)象躏尉,類型) # 判斷對(duì)象是否是指定類型,返回一個(gè)布爾類型

from collections import Iterable

# 判斷對(duì)象是否是指定類型

result = isinstance((3, 5), Iterable)

print("元組是否是可迭代對(duì)象:", result)

# 提示: 以后還根據(jù)對(duì)象判斷是否是其它類型,比如以后可以判斷函數(shù)里面的參數(shù)是否是自己想要的類型

result = isinstance(5, int)

print("整數(shù)是否是int類型對(duì)象:", result)

<4>自定義可迭代對(duì)象

自定義可迭代對(duì)象: 在類里面定義__iter__方法創(chuàng)建的對(duì)象就是可迭代對(duì)象

自定義可迭代類型代碼

from collections import Iterable

# 自定義可迭代對(duì)象: 在類里面定義__iter__方法創(chuàng)建的對(duì)象就是可迭代對(duì)象

class MyList(object):

? ? def __init__(self):

? ? ? ? self.my_list = list()

? ? # 添加指定元素

? ? def append_item(self, item):

? ? ? ? self.my_list.append(item)

? ? def __iter__(self):

? ? ? ? # 可迭代對(duì)象的本質(zhì):遍歷可迭代對(duì)象的時(shí)候其實(shí)獲取的是可迭代對(duì)象的迭代器后众, 然后通過(guò)迭代器獲取對(duì)象中的數(shù)據(jù)

# 可迭代對(duì)象的本質(zhì): 是通過(guò)迭代器幫助可迭代對(duì)象依次迭代對(duì)象中的每一個(gè)數(shù)據(jù),真正完成獲取數(shù)據(jù)的操作是通過(guò)迭代器完成的

? ? ? ? pass

my_list = MyList()

my_list.append_item(1)

my_list.append_item(2)

result = isinstance(my_list, Iterable)

print(result)

for value in my_list:

? ? print(value)

遍歷可迭代對(duì)象依次獲取數(shù)據(jù)需要迭代器

小結(jié)

在類里面提供一個(gè)__iter__創(chuàng)建的對(duì)象是可迭代對(duì)象胀糜,可迭代對(duì)象是需要迭代器完成數(shù)據(jù)迭代的。

2.迭代器

<1>自定義迭代器對(duì)象

自定義迭代器對(duì)象: 在類里面定義__iter__和__next__方法創(chuàng)建的對(duì)象就是迭代器對(duì)象

from collections import Iterable

from collections import Iterator

# 自定義可迭代對(duì)象: 在類里面定義__iter__方法創(chuàng)建的對(duì)象就是可迭代對(duì)象

class MyList(object):

? ? def __init__(self):

? ? ? ? self.my_list = list()

? ? # 添加指定元素

? ? def append_item(self, item):

? ? ? ? self.my_list.append(item)

? ? def __iter__(self):

? ? ? ? # 可迭代對(duì)象的本質(zhì):遍歷可迭代對(duì)象的時(shí)候其實(shí)獲取的是可迭代對(duì)象的迭代器蒂誉, 然后通過(guò)迭代器獲取對(duì)象中的數(shù)據(jù)

? ? ? ? my_iterator = MyIterator(self.my_list)

? ? ? ? return my_iterator

# 自定義迭代器對(duì)象: 在類里面定義__iter__和__next__方法創(chuàng)建的對(duì)象就是迭代器對(duì)象

class MyIterator(object):

? ? def __init__(self, my_list):

? ? ? ? self.my_list = my_list

? ? ? ? # 記錄當(dāng)前獲取數(shù)據(jù)的下標(biāo)

? ? ? ? self.current_index = 0

? ? ? ? # 判斷當(dāng)前對(duì)象是否是迭代器

? ? ? ? result = isinstance(self, Iterator)

? ? ? ? print("MyIterator創(chuàng)建的對(duì)象是否是迭代器:", result)

? ? def __iter__(self):

? ? ? ? return self

? ? # 獲取迭代器中下一個(gè)值

? ? def __next__(self):

? ? ? ? if self.current_index < len(self.my_list):

? ? ? ? ? ? self.current_index += 1

? ? ? ? ? ? return self.my_list[self.current_index - 1]

? ? ? ? else:

? ? ? ? ? ? # 數(shù)據(jù)取完了教藻,需要拋出一個(gè)停止迭代的異常

? ? ? ? ? ? raise StopIteration

my_list = MyList()

my_list.append_item(1)

my_list.append_item(2)

result = isinstance(my_list, Iterable)

print(result)

for value in my_list:

? ? print(value)

<2>iter()函數(shù)與next()函數(shù)

iter函數(shù): 獲取可迭代對(duì)象的迭代器,會(huì)調(diào)用可迭代對(duì)象身上的__iter__方法

next函數(shù): 獲取迭代器中下一個(gè)值右锨,會(huì)調(diào)用迭代器對(duì)象身上的__next__方法

# 自定義可迭代對(duì)象: 在類里面定義__iter__方法創(chuàng)建的對(duì)象就是可迭代對(duì)象

class MyList(object):

? ? def __init__(self):

? ? ? ? self.my_list = list()

? ? # 添加指定元素

? ? def append_item(self, item):

? ? ? ? self.my_list.append(item)

? ? def __iter__(self):

? ? ? ? # 可迭代對(duì)象的本質(zhì):遍歷可迭代對(duì)象的時(shí)候其實(shí)獲取的是可迭代對(duì)象的迭代器括堤, 然后通過(guò)迭代器獲取對(duì)象中的數(shù)據(jù)

? ? ? ? my_iterator = MyIterator(self.my_list)

? ? ? ? return my_iterator

# 自定義迭代器對(duì)象: 在類里面定義__iter__和__next__方法創(chuàng)建的對(duì)象就是迭代器對(duì)象

# 迭代器是記錄當(dāng)前數(shù)據(jù)的位置以便獲取下一個(gè)位置的值

class MyIterator(object):

? ? def __init__(self, my_list):

? ? ? ? self.my_list = my_list

? ? ? ? # 記錄當(dāng)前獲取數(shù)據(jù)的下標(biāo)

? ? ? ? self.current_index = 0

? ? def __iter__(self):

? ? ? ? return self

? ? # 獲取迭代器中下一個(gè)值

? ? def __next__(self):

? ? ? ? if self.current_index < len(self.my_list):

? ? ? ? ? ? self.current_index += 1

? ? ? ? ? ? return self.my_list[self.current_index - 1]

? ? ? ? else:

? ? ? ? ? ? # 數(shù)據(jù)取完了,需要拋出一個(gè)停止迭代的異常

? ? ? ? ? ? raise StopIteration

# 創(chuàng)建了一個(gè)自定義的可迭代對(duì)象

my_list = MyList()

my_list.append_item(1)

my_list.append_item(2)

# 獲取可迭代對(duì)象的迭代器

my_iterator = iter(my_list)

print(my_iterator)

# 獲取迭代器中下一個(gè)值

# value = next(my_iterator)

# print(value)

# 循環(huán)通過(guò)迭代器獲取數(shù)據(jù)

while True:

? ? try:

? ? ? ? value = next(my_iterator)

? ? ? ? print(value)

? ? except StopIteration as e:

? ? ? ? break

<3>for循環(huán)的本質(zhì)

遍歷的是可迭代對(duì)象

? for item in Iterable 循環(huán)的本質(zhì)就是先通過(guò)iter()函數(shù)獲取可迭代對(duì)象Iterable的迭代器绍移,然后對(duì)獲取到的迭代器不斷調(diào)用next()方法來(lái)獲取下一個(gè)值并將其賦值給item悄窃,當(dāng)遇到StopIteration的異常后循環(huán)結(jié)束。

遍歷的是迭代器

? for item in Iterator 循環(huán)的迭代器蹂窖,不斷調(diào)用next()方法來(lái)獲取下一個(gè)值并將其賦值給item轧抗,當(dāng)遇到StopIteration的異常后循環(huán)結(jié)束。

for循環(huán)內(nèi)部自動(dòng)捕獲停止迭代的異常瞬测,而while循環(huán)內(nèi)部沒有自己捕獲

最終取值操作都是通過(guò)迭代器完成的

<4>迭代器的應(yīng)用場(chǎng)景

我們發(fā)現(xiàn)迭代器最核心的功能就是可以通過(guò)next()函數(shù)的調(diào)用來(lái)返回下一個(gè)數(shù)據(jù)值横媚。如果每次返回的數(shù)據(jù)值不是在一個(gè)已有的數(shù)據(jù)集合中讀取的,而是通過(guò)程序按照一定的規(guī)律計(jì)算生成的月趟,那么也就意味著可以不用再依賴一個(gè)已有的數(shù)據(jù)集合灯蝴,也就是說(shuō)不用再將所有要迭代的數(shù)據(jù)都一次性緩存下來(lái)供后續(xù)依次讀取,這樣可以節(jié)省大量的存儲(chǔ)(內(nèi)存)空間孝宗。

舉個(gè)例子绽乔,比如,數(shù)學(xué)中有個(gè)著名的斐波拉契數(shù)列(Fibonacci)碳褒,數(shù)列中第一個(gè)數(shù)為0折砸,第二個(gè)數(shù)為1,其后的每一個(gè)數(shù)都可由前兩個(gè)數(shù)相加得到:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

現(xiàn)在我們想要通過(guò)for...in...循環(huán)來(lái)遍歷迭代斐波那契數(shù)列中的前n個(gè)數(shù)沙峻。那么這個(gè)斐波那契數(shù)列我們就可以用迭代器來(lái)實(shí)現(xiàn)睦授,每次迭代都通過(guò)數(shù)學(xué)計(jì)算來(lái)生成下一個(gè)數(shù)。

迭代器完成斐波那契的好處:

? 節(jié)省內(nèi)存空間摔寨,因?yàn)槊看胃鶕?jù)算法只生成一個(gè)值

? 生成數(shù)列的個(gè)數(shù)沒有上限控制

class Fibonacci(object):

? ? def __init__(self, num):

? ? ? ? # num:表示生成多少fibonacci數(shù)字

? ? ? ? self.num = num

? ? ? ? # 記錄fibonacci前兩個(gè)值

? ? ? ? self.a = 0

? ? ? ? self.b = 1

? ? ? ? # 記錄當(dāng)前生成數(shù)字的索引

? ? ? ? self.current_index = 0

? ? def __iter__(self):

? ? ? ? return self

? ? def __next__(self):

? ? ? ? if self.current_index < self.num:

? ? ? ? ? ? result = self.a

? ? ? ? ? ? self.a, self.b = self.b, self.a + self.b

? ? ? ? ? ? self.current_index += 1

? ? ? ? ? ? return result

? ? ? ? else:

? ? ? ? ? ? raise StopIteration

fib = Fibonacci(5)

# value = next(fib)

# print(value)

for value in fib:

? ? print(value)

小結(jié)

迭代器的作用就是是記錄當(dāng)前數(shù)據(jù)的位置以便獲取下一個(gè)位置的值

3.生成器

<1>生成器的概念

生成器是一類特殊的迭代器,它不需要再像上面的類一樣寫__iter__()和__next__()方法了, 使用更加方便,它依然可以使用next函數(shù)和for循環(huán)取值

<2>創(chuàng)建生成器方法1

? 第一種方法很簡(jiǎn)單去枷,只要把一個(gè)列表推導(dǎo)式的 [ ] 改成 ( )

my_list = [i * 2 for i in range(5)]

print(my_list)

# 創(chuàng)建生成器

my_generator = (i * 2 for i in range(5))

print(my_generator)

# next獲取生成器下一個(gè)值

# value = next(my_generator)

# print(value)

for value in my_generator:

? ? print(value)

<3>創(chuàng)建生成器方法2

在def函數(shù)里面看到有yield關(guān)鍵字那么就是生成器

def fibonacci(num):

? ? a = 0

? ? b = 1

? ? # 記錄生成fibonacci數(shù)字的下標(biāo)

? ? current_index = 0

? ? print("--11---")

? ? while current_index < num:

? ? ? ? result = a

? ? ? ? a, b = b, a + b

? ? ? ? current_index += 1

? ? ? ? print("--22---")

? ? ? ? # 代碼執(zhí)行到y(tǒng)ield會(huì)暫停,然后把結(jié)果返回出去,下次啟動(dòng)生成器會(huì)在暫停的位置繼續(xù)往下執(zhí)行

? ? ? ? yield result

? ? ? ? print("--33---")

fib = fibonacci(5)

value = next(fib)

print(value)

value = next(fib)

print(value)

value = next(fib)

print(value)

# for value in fib:

#? ? print(value)

在使用生成器實(shí)現(xiàn)的方式中删顶,我們將原本在迭代器__next__方法中實(shí)現(xiàn)的基本邏輯放到一個(gè)函數(shù)中來(lái)實(shí)現(xiàn)竖螃,但是將每次迭代返回?cái)?shù)值的return換成了yield,此時(shí)新定義的函數(shù)便不再是函數(shù)逗余,而是一個(gè)生成器了特咆。

簡(jiǎn)單來(lái)說(shuō):只要在def中有yield關(guān)鍵字的 就稱為 生成器

<4>生成器使用return關(guān)鍵字

def fibonacci(num):

? ? a = 0

? ? b = 1

? ? # 記錄生成fibonacci數(shù)字的下標(biāo)

? ? current_index = 0

? ? print("--11---")

? ? while current_index < num:

? ? ? ? result = a

? ? ? ? a, b = b, a + b

? ? ? ? current_index += 1

? ? ? ? print("--22---")

? ? ? ? # 代碼執(zhí)行到y(tǒng)ield會(huì)暫停,然后把結(jié)果返回出去录粱,下次啟動(dòng)生成器會(huì)在暫停的位置繼續(xù)往下執(zhí)行

? ? ? ? yield result

? ? ? ? print("--33---")

? ? ? ? return "嘻嘻"

fib = fibonacci(5)

value = next(fib)

print(value)

# 提示: 生成器里面使用return關(guān)鍵字語(yǔ)法上沒有問(wèn)題腻格,但是代碼執(zhí)行到return語(yǔ)句會(huì)停止迭代,拋出停止迭代異常

# 在python3里面可以使用return關(guān)鍵字啥繁,python2不支持

# return 和 yield的區(qū)別

# yield: 每次啟動(dòng)生成器都會(huì)返回一個(gè)值菜职,多次啟動(dòng)可以返回多個(gè)值,也就是yield可以返回多個(gè)值

# return: 只能返回一次值旗闽,代碼執(zhí)行到return語(yǔ)句就停止迭代

try:

? ? value = next(fib)

? ? print(value)

except StopIteration as e:

? ? # 獲取return的返回值

? ? print(e.value)

提示:

? 生成器里面使用return關(guān)鍵字語(yǔ)法上沒有問(wèn)題酬核,但是代碼執(zhí)行到return語(yǔ)句會(huì)停止迭代,拋出停止迭代異常

? 在python3里面可以使用return關(guān)鍵字适室,python2不支持

<5>yield和return的對(duì)比

? 使用了yield關(guān)鍵字的函數(shù)不再是函數(shù)愁茁,而是生成器。(使用了yield的函數(shù)就是生成器)

? 代碼執(zhí)行到y(tǒng)ield會(huì)暫停亭病,然后把結(jié)果返回出去鹅很,下次啟動(dòng)生成器會(huì)在暫停的位置繼續(xù)往下執(zhí)行

? 每次啟動(dòng)生成器都會(huì)返回一個(gè)值,多次啟動(dòng)可以返回多個(gè)值罪帖,也就是yield可以返回多個(gè)值

? return只能返回一次值促煮,代碼執(zhí)行到return語(yǔ)句就停止迭代,拋出停止迭代異常

<6>使用send方法啟動(dòng)生成器并傳參

send方法啟動(dòng)生成器的時(shí)候可以傳參數(shù)

def gen():

i = 0

while i<5:

temp = yield i

print(temp)

i+=1

next? 和 send的區(qū)別:

? next函數(shù)啟動(dòng)生成器不能傳入?yún)?shù)

? send方法啟動(dòng)生成器可以傳入?yún)?shù),但是第一次只能傳入None

注意:

如果第一次啟動(dòng)生成器使用send方法整袁,那么參數(shù)只能傳入None,一般第一次啟動(dòng)生成器使用next函數(shù)

小結(jié)

? 生成器創(chuàng)建有兩種方式菠齿,一般都使用yield關(guān)鍵字方法創(chuàng)建生成器

? yield特點(diǎn)是代碼執(zhí)行到y(tǒng)ield會(huì)暫停,把結(jié)果返回出去坐昙,再次啟動(dòng)生成器在暫停的位置繼續(xù)往下執(zhí)行

4.協(xié)程

<1>協(xié)程的概念

協(xié)程绳匀,又稱微線程,纖程,也稱為用戶級(jí)線程炸客,在不開辟線程的基礎(chǔ)上完成多任務(wù)疾棵,也就是在單線程的情況下完成多任務(wù),多個(gè)任務(wù)按照一定順序交替執(zhí)行 通俗理解只要在def里面只看到一個(gè)yield關(guān)鍵字表示就是協(xié)程

協(xié)程是也是實(shí)現(xiàn)多任務(wù)的一種方式

協(xié)程yield的代碼實(shí)現(xiàn)

import time

def work1():

? ? while True:

? ? ? ? print("----work1---")

? ? ? ? yield

? ? ? ? time.sleep(0.5)

def work2():

? ? while True:

? ? ? ? print("----work2---")

? ? ? ? yield

? ? ? ? time.sleep(0.5)

def main():

? ? w1 = work1()

? ? w2 = work2()

? ? while True:

? ? ? ? next(w1)

? ? ? ? next(w2)

if __name__ == "__main__":

? ? main()

小結(jié):

協(xié)程之間執(zhí)行任務(wù)按照一定順序交替執(zhí)行

5.greenlet

<1>greentlet的介紹

為了更好使用協(xié)程來(lái)完成多任務(wù)痹仙,python中的greenlet模塊對(duì)其封裝是尔,從而使得切換任務(wù)變的更加簡(jiǎn)單

使用如下命令安裝greenlet模塊:

pip3 install greenlet

import time

import greenlet

# 任務(wù)1

def work1():

? ? for i in range(5):

? ? ? ? print("work1...")

? ? ? ? time.sleep(0.2)

? ? ? ? # 切換到協(xié)程2里面執(zhí)行對(duì)應(yīng)的任務(wù)

? ? ? ? g2.switch()

# 任務(wù)2

def work2():

? ? for i in range(5):

? ? ? ? print("work2...")

? ? ? ? time.sleep(0.2)

? ? ? ? # 切換到第一個(gè)協(xié)程執(zhí)行對(duì)應(yīng)的任務(wù)

? ? ? ? g1.switch()

if __name__ == '__main__':

? ? # 創(chuàng)建協(xié)程指定對(duì)應(yīng)的任務(wù)

? ? g1 = greenlet.greenlet(work1)

? ? g2 = greenlet.greenlet(work2)

? ? # 切換到第一個(gè)協(xié)程執(zhí)行對(duì)應(yīng)的任務(wù)

? ? g1.switch()

6.gevent

<1>gevent的介紹

greenlet已經(jīng)實(shí)現(xiàn)了協(xié)程,但是這個(gè)還要人工切換开仰,這里介紹一個(gè)比greenlet更強(qiáng)大而且能夠自動(dòng)切換任務(wù)的第三方庫(kù)拟枚,那就是gevent薪铜。

gevent內(nèi)部封裝的greenlet,其原理是當(dāng)一個(gè)greenlet遇到IO(指的是input output 輸入輸出恩溅,比如網(wǎng)絡(luò)隔箍、文件操作等)操作時(shí),比如訪問(wèn)網(wǎng)絡(luò)脚乡,就自動(dòng)切換到其他的greenlet蜒滩,等到IO操作完成,再在適當(dāng)?shù)臅r(shí)候切換回來(lái)繼續(xù)執(zhí)行每窖。

由于IO操作非常耗時(shí)帮掉,經(jīng)常使程序處于等待狀態(tài)弦悉,有了gevent為我們自動(dòng)切換協(xié)程窒典,就保證總有g(shù)reenlet在運(yùn)行,而不是等待IO

安裝

pip3 install gevent

<2>gevent的使用

import gevent

def work(n):

? ? for i in range(n):

? ? ? ? # 獲取當(dāng)前協(xié)程gevent.getcurrent()

? ? ? ? print(gevent.getcurrent(), i)

g1 = gevent.spawn(work, 5)

g2 = gevent.spawn(work, 5)

g3 = gevent.spawn(work, 5)

g1.join()

g2.join()

g3.join()

3個(gè)greenlet是依次運(yùn)行而不是交替運(yùn)行

<3>gevent切換執(zhí)行

import gevent

def work(n):

? ? for i in range(n):

? ? ? ? # 獲取當(dāng)前協(xié)程

? ? ? ? print(gevent.getcurrent(), i)

? ? ? ? #用來(lái)模擬一個(gè)耗時(shí)操作稽莉,注意不是time模塊中的sleep

? ? ? ? gevent.sleep(1)

g1 = gevent.spawn(work, 5)

g2 = gevent.spawn(work, 5)

g3 = gevent.spawn(work, 5)

g1.join()

g2.join()

g3.join()

<4>給程序打補(bǔ)丁

gevent默認(rèn)不會(huì)認(rèn)為系統(tǒng)的耗時(shí)操作是耗時(shí)的瀑志,不識(shí)別time.sleep,accept,recv等,需要打補(bǔ)丁

import gevent

import time

from gevent import monkey

# 打補(bǔ)丁污秆,讓gevent框架識(shí)別耗時(shí)操作劈猪,比如:time.sleep,accept,recv,網(wǎng)絡(luò)請(qǐng)求延時(shí)等

monkey.patch_all()

# 任務(wù)1

def work1(num):

? ? for i in range(num):

? ? ? ? print("work1....")

? ? ? ? time.sleep(0.2)

? ? ? ? # gevent.sleep(0.2)

# 任務(wù)1

def work2(num):

? ? for i in range(num):

? ? ? ? print("work2....")

? ? ? ? time.sleep(0.2)

? ? ? ? # gevent.sleep(0.2)

if __name__ == '__main__':

? ? # 創(chuàng)建協(xié)程指定對(duì)應(yīng)的任務(wù)

? ? g1 = gevent.spawn(work1, 3)

? ? g2 = gevent.spawn(work2, 3)

? ? # 主線程等待協(xié)程執(zhí)行完成以后程序再退出

? ? g1.join()

? ? g2.join()

<5>注意

? 當(dāng)前程序是一個(gè)死循環(huán)并且還能有耗時(shí)操作,就不需要加上join方法了,因?yàn)槌绦蛐枰恢边\(yùn)行不會(huì)退出

示例代碼

import gevent

import time

from gevent import monkey

# 打補(bǔ)丁良拼,讓gevent框架識(shí)別耗時(shí)操作战得,比如:time.sleep,網(wǎng)絡(luò)請(qǐng)求延時(shí)

monkey.patch_all()

# 任務(wù)1

def work1(num):

? ? for i in range(num):

? ? ? ? print("work1....")

? ? ? ? time.sleep(0.2)

? ? ? ? # gevent.sleep(0.2)

# 任務(wù)1

def work2(num):

? ? for i in range(num):

? ? ? ? print("work2....")

? ? ? ? time.sleep(0.2)

? ? ? ? # gevent.sleep(0.2)

if __name__ == '__main__':

? ? # 創(chuàng)建協(xié)程指定對(duì)應(yīng)的任務(wù)

? ? g1 = gevent.spawn(work1, 3)

? ? g2 = gevent.spawn(work2, 3)

? ? while True:

? ? ? ? print("主線程中執(zhí)行")

? ? ? ? time.sleep(0.5)

7.進(jìn)程庸推、線程常侦、協(xié)程對(duì)比

<1>進(jìn)程、線程贬媒、協(xié)程之間的關(guān)系

? 一個(gè)進(jìn)程至少有一個(gè)線程聋亡,進(jìn)程里面可以有多個(gè)線程

? 一個(gè)線程里面可以有多個(gè)協(xié)程

<2>進(jìn)程、線程际乘、線程的對(duì)比

? 進(jìn)程是系統(tǒng)資源分配的基本單位

? 線程是操作系統(tǒng)調(diào)度的基本單位

? 進(jìn)程切換需要的資源最大坡倔,效率很低

? 線程切換需要的資源一般,效率一般(當(dāng)然了在不考慮GIL的情況下)

? 協(xié)程切換任務(wù)資源很小脖含,效率高

? 多進(jìn)程罪塔、多線程根據(jù)cpu核數(shù)不一樣可能是并行的,但是協(xié)程是在一個(gè)線程中 所以是并發(fā)

小結(jié)

? 進(jìn)程养葵、線程垢袱、協(xié)程都是可以完成多任務(wù)的,可以根據(jù)自己實(shí)際開發(fā)的需要選擇使用

? 由于線程港柜、協(xié)程需要的資源很少请契,所以使用線程和協(xié)程的幾率最大

? 開辟協(xié)程需要的資源最少

? 協(xié)程和線程的區(qū)別是:協(xié)程避免了無(wú)意義的調(diào)度咳榜,由此可以提高性能,但也因此爽锥,程序員必須自己承擔(dān)調(diào)度的責(zé)任涌韩,同時(shí),協(xié)程也失去了標(biāo)準(zhǔn)線程使用多CPU的能力臣樱。

? 進(jìn)程擁有自己獨(dú)立的堆和棧,既不共享堆腮考,亦不共享?xiàng)9秃粒M(jìn)程由操作系統(tǒng)調(diào)度。

? 線程擁有自己獨(dú)立的棧和共享的堆踩蔚,共享堆棚放,不共享?xiàng)#€程亦由操作系統(tǒng)調(diào)度(標(biāo)準(zhǔn)線程是的)

8.gevent多任務(wù)圖片下載

<1>多任務(wù)圖片下載的示例代碼

import gevent

import urllib.request # 網(wǎng)絡(luò)請(qǐng)求模塊

from gevent import monkey

# 打補(bǔ)断诿觥: 讓gevent使用網(wǎng)絡(luò)請(qǐng)求的耗時(shí)操作飘蚯,讓協(xié)程自動(dòng)切換執(zhí)行對(duì)應(yīng)的下載任務(wù)

monkey.patch_all()

# 根據(jù)圖片地址下載對(duì)應(yīng)的圖片

def download_img(img_url, img_name):

? ? try:

? ? ? ? print(img_url)

? ? ? ? # 根據(jù)圖片地址打開網(wǎng)絡(luò)資源數(shù)據(jù)

? ? ? ? response = urllib.request.urlopen(img_url)

? ? ? ? # 創(chuàng)建文件把數(shù)據(jù)寫入到指定文件里面

? ? ? ? with open(img_name, "wb") as img_file:

? ? ? ? ? ? while True:

? ? ? ? ? ? ? ? # 讀取網(wǎng)絡(luò)圖片數(shù)據(jù)

? ? ? ? ? ? ? ? img_data = response.read(1024)

? ? ? ? ? ? ? ? if img_data:

? ? ? ? ? ? ? ? ? ? # 把數(shù)據(jù)寫入到指定文件里面

? ? ? ? ? ? ? ? ? ? img_file.write(img_data)

? ? ? ? ? ? ? ? else:

? ? ? ? ? ? ? ? ? ? break

? ? except Exception as e:

? ? ? ? print("圖片下載異常:", e)

? ? else:

? ? ? ? print("圖片下載成功: %s" % img_name)

if __name__ == '__main__':

? ? # 準(zhǔn)備圖片地址

? ? img_url1 = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=551346117,2593226454&fm=27&gp=0.jpg"

? ? img_url2 = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=829730016,3409799239&fm=27&gp=0.jpg"

? ? img_url3 = "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1815077192,817368579&fm=27&gp=0.jpg"

? ? # 創(chuàng)建協(xié)程指派對(duì)應(yīng)的任務(wù)

? ? g1 = gevent.spawn(download_img, img_url1, "1.jpg")

? ? g2 = gevent.spawn(download_img, img_url2, "2.jpg")

? ? g3 = gevent.spawn(download_img, img_url3, "3.jpg")

? ? # 主線程等待所有的協(xié)程執(zhí)行完成以后程序再退出

? ? gevent.joinall([g1, g2, g3])

依次根據(jù)圖片地址去下載,但是收到數(shù)據(jù)的先后順序不一定與發(fā)送順序相同福也,這也就體現(xiàn)出了異步局骤,即不確定什么時(shí)候會(huì)收到數(shù)據(jù),順序不一定


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暴凑,一起剝皮案震驚了整個(gè)濱河市峦甩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌现喳,老刑警劉巖凯傲,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拿穴,居然都是意外死亡泣洞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門默色,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)球凰,“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了欲险?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)甩挫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)椿每,這世上最難降的妖魔是什么伊者? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任英遭,我火速辦了婚禮,結(jié)果婚禮上亦渗,老公的妹妹穿的比我還像新娘挖诸。我一直安慰自己,他們只是感情好法精,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布多律。 她就那樣靜靜地躺著,像睡著了一般搂蜓。 火紅的嫁衣襯著肌膚如雪狼荞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天帮碰,我揣著相機(jī)與錄音相味,去河邊找鬼。 笑死收毫,一個(gè)胖子當(dāng)著我的面吹牛攻走,可吹牛的內(nèi)容都是我干的殷勘。 我是一名探鬼主播此再,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼玲销!你這毒婦竟也來(lái)了输拇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贤斜,失蹤者是張志新(化名)和其女友劉穎策吠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘩绒,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猴抹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锁荔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蟀给。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖阳堕,靈堂內(nèi)的尸體忽然破棺而出跋理,到底是詐尸還是另有隱情,我是刑警寧澤恬总,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布前普,位于F島的核電站,受9級(jí)特大地震影響壹堰,放射性物質(zhì)發(fā)生泄漏拭卿。R本人自食惡果不足惜骡湖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望峻厚。 院中可真熱鬧勺鸦,春花似錦、人聲如沸目木。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刽射。三九已至军拟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間誓禁,已是汗流浹背懈息。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摹恰,地道東北人辫继。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像俗慈,于是被迫代替她去往敵國(guó)和親姑宽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容