版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第Python利用contextvars實現(xiàn)管理上下文變量"""
先awaitget2()得到的就是set_函數(shù)中設置的值,這是符合預期的。但是我們在get1中將值重新設置了,那么之后不管是awaitget1()還是直接awaitget2(),得到的都是新設置的值。
這也說明了,一個協(xié)程內部await另一個協(xié)程,另一個協(xié)程內部await另另一個協(xié)程,不管套娃(await)多少次,它們獲取的值都是一樣的。并且在任意一個協(xié)程內部都可以重新設置值,然后獲取會得到最后一次設置的值。再舉個栗子:
import
asyncio
import
contextvars
c
=
contextvars.ContextVar("只是一個標識,
用于調試")
async
def
get1():
return
await
get2()
async
def
get2():
val
=
c.get()
+
"~~~"
c.set("重新設置啦")
return
val
async
def
set_(val):
#
設置值
c.set(val)
print(await
get1())
print(c.get())
async
def
main():
coro
=
set_("古明地覺")
await
coro
asyncio.run(main())
古明地覺~~~
重新設置啦
"""
awaitget1()的時候會執(zhí)行awaitget2(),然后在里面拿到c.set設置的值,打印古明地覺~~~。但是在get2里面,又將值重新設置了,所以第二個print打印的就是新設置的值。\
如果在get之前沒有先set,那么會拋出一個LookupError,所以ContextVar支持默認值:
import
asyncio
import
contextvars
c
=
contextvars.ContextVar("只是一個標識,
用于調試",
default="哼哼")
async
def
set_(val):
print(c.get())
c.set(val)
print(c.get())
async
def
main():
coro
=
set_("古明地覺")
await
coro
asyncio.run(main())
"""
除了在ContextVar中指定默認值之外,也可以在get中指定:
import
asyncio
import
contextvars
c
=
contextvars.ContextVar("只是一個標識,
用于調試",
default="哼哼")
async
def
set_(val):
print(c.get("古明地戀"))
c.set(val)
print(c.get())
async
def
main():
coro
=
set_("古明地覺")
await
coro
asyncio.run(main())
"""
所以結論如下,如果在c.set之前使用c.get:
當ContextVar和get中都沒有指定默認值,會拋出LookupError;只要有一方設置了,那么會得到默認值;如果都設置了,那么以get為準;
如果c.get之前執(zhí)行了c.set,那么無論ContextVar和get有沒有指定默認值,獲取到的都是c.set設置的值。
所以總的來說還是比較好理解的,并且ContextVar除了可以作用在協(xié)程上面,它也可以用在線程上面。沒錯,它可以替代threading.local,我們來試一下:
import
threading
import
contextvars
c
=
contextvars.ContextVar("context_var")
def
get():
name
=
threading.current_thread().name
value
=
c.get()
print(f"線程
{name},
value:
{value}")
def
set_():
name
=
threading.current_thread().name
if
name
==
"one":
c.set("ONE")
elif
name
==
"two":
c.set("TWO")
get()
t1
=
threading.Thread(target=set_,
name="one")
t2
=
threading.Thread(target=set_,
name="two")
t1.start()
t2.start()
線程
one,
value:
ONE
線程
two,
value:
TWO
"""
和threading.local的表現(xiàn)是一樣的,但是更建議使用ContextVars。不過前者可以綁定任意多個值,而后者只能綁定一個值(可以通過傳遞字典的方式解決這一點)。
c.Token
當我們調用c.set的時候,其實會返回一個Token對象:
import
contextvars
c
=
contextvars.ContextVar("context_var")
token
=
c.set("val")
print(token)
Token
var=ContextVar
name='context_var'
at
0x00..
at
0x00...
"""
Token對象有一個var屬性,它是只讀的,會返回指向此token的ContextVar對象。
import
contextvars
c
=
contextvars.ContextVar("context_var")
token
=
c.set("val")
print(token.var
is
c)
#
True
print(token.var.get())
#
val
print(
token.var.set("val2").var.set("val3").var
is
c
)#
True
print(c.get())
#
val3
Token對象還有一個old_value屬性,它會返回上一次set設置的值,如果是第一次set,那么會返回一個Token.MISSING。
import
contextvars
c
=
contextvars.ContextVar("context_var")
token
=
c.set("val")
#
該
token
是第一次
c.set
所返回的
#
在此之前沒有
set,所以
old_value
是
Token.MISSING
print(token.old_value)
#
Token.MISSING
token
=
c.set("val2")
print(c.get())
#
val2
#
返回上一次
set
的值
print(token.old_value)
#
val
那么這個Token對象有什么作用呢?從目前來看貌似沒太大用處啊,其實它最大的用處就是和reset搭配使用,可以對狀態(tài)進行重置。
import
contextvars
####
c
=
contextvars.ContextVar("context_var")
token
=
c.set("val")
#
顯然是可以獲取的
print(c.get())
#
val
#
將其重置為
token
之前的狀態(tài)
#
但這個
token
是第一次
set
返回的
#
那么之前就相當于沒有
set
了
c.reset(token)
c.get()
#
此時就會報錯
except
LookupError:
print("報錯啦")
#
報錯啦
#
但是我們可以指定默認值
print(c.get("默認值"))
#
默認值
contextvars.Context
它負責保存ContextVars對象和設置的值之間的映射,但是我們不會直接通過contextvars.Context來創(chuàng)建,而是通過contentvars.copy_context函數(shù)來創(chuàng)建。
import
contextvars
c1
=
contextvars.ContextVar("context_var1")
c1.set("val1")
c2
=
contextvars.ContextVar("context_var2")
c2.set("val2")
#
此時得到的是所有
ContextVar
對象和設置的值之間的映射
#
它實現(xiàn)了
collections.abc.Mapping
接口
#
因此我們可以像操作字典一樣操作它
context
=
contextvars.copy_context()
#
key
就是對應的
ContextVar
對象,value
就是設置的值
print(context[c1])
#
val1
print(context[c2])
#
val2
for
ctx,
value
in
context.items():
print(ctx.get(),
,
value)
"""
val1
context_var1
val1
val2
context_var2
val2
"""
print(len(context))
#
2
除此之外,context還有一個run方法:
import
contextvars
c1
=
contextvars.ContextVar("context_var1")
c1.set("val1")
c2
=
contextvars.ContextVar("context_var2")
c2.set("val2")
context
=
contextvars.copy_context()
def
change(val1,
val2):
c1.set(val1)
c2.set(val2)
print(c1.get(),
context[c1])
print(c2.get(),
context[c2])
#
在
change
函數(shù)內部,重新設置值
#
然后里面打印的也是新設置的值
context.run(change,
"VAL1",
"VAL2")
VAL1
VAL1
VAL2
VAL2
print(c1.get(),
context[c1])
print(c2.get(),
context[c2])
val1
VAL1
val2
VAL2
"""
我們看到run方法接收一個callable,如果在里面修改了ContextVar實例設置的值,那么對于ContextVar而言只會在函數(shù)內部生效,一旦出了函數(shù),那么還是原來的值。但是對于Context而言,它是會受到影響的,即便出了函數(shù),也是新設置的值,因為它直接把內部的字典給修改了。
小結
以上就是contextvars模塊的用法,在多個協(xié)程之間傳遞數(shù)據(jù)是非常方便的,并且也是并發(fā)安全的。如果你用過Go的話,你
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 裁線機安全培訓課件
- 表計計量安裝培訓課件
- 蛋糕店烘焙知識培訓課件
- 急救護理學趣味
- 中醫(yī)藥文化資源
- 根管治療術的健康宣教
- 馬嵬其二課件
- 2026屆新高考化學沖刺復習-以硫酸亞鐵銨的制備和氧化還原滴定為載體的實驗復習
- 食品安全風險監(jiān)測培訓課件
- 2026屆重慶市一中數(shù)學高一上期末考試模擬試題含解析
- 14J936《變形縫建筑構造》
- 魯班鎖魯班球課件
- 新概念英語第二冊階段一練習冊
- 2024屆河北省石家莊市普通高中學校畢業(yè)年級教學質量摸底檢測物理試卷含答案
- 建設工程施工內部承包協(xié)議
- 【角色游戲對對幼兒社會性發(fā)展影響及促進對策7900字(論文)】
- 第四講 Meta分析的數(shù)據(jù)提取與分析-課件
- 宮內節(jié)育器放置術
- 新制定《無障礙環(huán)境建設法》主題PPT
- 期末復習主題班會
- 道路交通基礎設施韌性提升
評論
0/150
提交評論