欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

Python3中contextvars模塊是什么-創(chuàng)新互聯(lián)

創(chuàng)新互聯(lián)www.cdcxhl.cn八線動(dòng)態(tài)BGP香港云服務(wù)器提供商,新人活動(dòng)買多久送多久,劃算不套路!

為大通等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及大通網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、大通網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

不懂Python3中contextvars模塊是什么?其實(shí)想解決這個(gè)問題也不難,下面讓小編帶著大家一起學(xué)習(xí)怎么去解決,希望大家閱讀完這篇文章后大所收獲。

什么是上下文(Context)?

Context Variables,也就是「上下文變量」。

Python3中contextvars模塊是什么

Context是一個(gè)包含了相關(guān)環(huán)境內(nèi)容的對(duì)象。這不是什么很高深的設(shè)計(jì),其實(shí)和我們的日常生活也是息息相關(guān)的。

舉個(gè)比較實(shí)時(shí)的例子,權(quán)力的游戲第八季剛開播,如果你沒看過前七季,不了解過去的劇情、人物關(guān)系、過去的種種主線副線發(fā)展,去看第八季第一集是完全看不懂的,因?yàn)槟闳笔Я诉@個(gè)美劇的上下文。

上下文就帶著這些信息,如果有一人非常了解過去的那些劇情甚至看過原著,Ta可以把那些第八季能關(guān)聯(lián)到的故事、劇情搞一個(gè)視頻剪輯(上下文對(duì)象),那么你不需要把過去完整的七季完整看一遍,可能花一個(gè)小時(shí)看看這個(gè)視頻(獲得上下文對(duì)象),就能繼續(xù)看第八季(完成之后的操作)。

Flask的設(shè)計(jì)中就包含了Context(下面不再說上下文,而統(tǒng)一用Context)。這個(gè)設(shè)計(jì)有什么用呢?簡(jiǎn)單地說:可以在一些場(chǎng)景下隱式地傳遞變量

我們看一下Django和Sanic怎么傳遞請(qǐng)求對(duì)象Request:

# Django
from django.http import HttpResponse
def index(request):
    text = request.GET.get('text')
    return HttpResponse(f'Text is {text}')
# Sanic
from sanic import response
app = Sanic()
@app.route('/')
async def index(request):
    text = request.args.get('text')
    return response.text(f'Text is {text}')

這2個(gè)框架都有一個(gè)問題:視圖函數(shù)上要顯式的傳遞request(請(qǐng)求對(duì)象)。我們?cè)倏纯碏lask的效果:

from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def index():
    text = request.args.get('text')
    return f'Text is {text}'

在Flask中,request是import進(jìn)來使用的(不需要就不用import),和視圖解耦了。這種設(shè)計(jì)下,不需要像Django/Sanic那樣把參數(shù)傳來傳去。

ThreadLocal

Flask怎么實(shí)現(xiàn)的呢?這就引出了ThreadLocal(本地線程)對(duì)象,看名字可以知道它是線程安全的,是單個(gè)線程自己的局部變量。Flask的實(shí)現(xiàn)中并沒有直接用Python的ThreadLocal,而是自己實(shí)現(xiàn)了一個(gè)Local類,除了支持線程還支持了Greenlet的協(xié)程。

Q: 那為什么不用全局變量呢? A: 由于存在GIL,全局變量的修改必須加鎖,會(huì)影響效率

先看一下線程庫(kù)中ThreadLocal的例子:

? cat threadlocal_example.py
import random
import threading
local_data = threading.local()
def show():
    name = threading.current_thread().getName()
    try:
        val = local_data.value
    except AttributeError:
        print(f'Thread {name}: No value yet')
    else:
        print(f'Thread {name}: {val}')
def worker():
    show()
    local_data.value = random.randint(1, 100)
    show()
for i in range(2):
    t = threading.Thread(target=worker)
    t.start()
? python threadlocal_example.py
Thread Thread-1: No value yet
Thread Thread-1: 78
Thread Thread-2: No value yet
Thread Thread-2: 64

可以感受到2個(gè)線程的狀態(tài)互不影響?;氐紽lask,請(qǐng)求Context在內(nèi)部作為一個(gè)棧來維護(hù)(應(yīng)用Context在另外一個(gè)棧)。每個(gè)訪問Flask的請(qǐng)求,會(huì)綁定到當(dāng)前的Context,等請(qǐng)求結(jié)束后再銷毀。維護(hù)的過程由框架實(shí)現(xiàn),開發(fā)者不需要關(guān)心,你只需要用flask.request就可以了,這樣就提高了接口的可讀性和擴(kuò)展性。

contextvars例子

threading.local的隔離效果很好,但是他是針對(duì)線程的,隔離線程之間的數(shù)據(jù)狀態(tài)。但是現(xiàn)在有了asyncio,怎么辦?

biu~ 我們回到contextvars,這個(gè)模塊提供了一組接口,可用于管理、儲(chǔ)存、訪問局部Context的狀態(tài)。我們看個(gè)例子:

? cat contextvar_example.py
import asyncio
import contextvars
# 申明Context變量
request_id = contextvars.ContextVar('Id of request')
async def get():
    # Get Value
    print(f'Request ID (Inner): {request_id.get()}')
async def new_coro(req_id):
    # Set Value
    request_id.set(req_id)
    await get()
    print(f'Request ID (Outer): {request_id.get()}')
async def main():
    tasks = []
    for req_id in range(1, 5):
        tasks.append(asyncio.create_task(new_coro(req_id)))
    await asyncio.gather(*tasks)
asyncio.run(main())
? python contextvar_example.py
Request ID (Inner): 1
Request ID (Outer): 1
Request ID (Inner): 2
Request ID (Outer): 2
Request ID (Inner): 3
Request ID (Outer): 3
Request ID (Inner): 4
Request ID (Outer): 4

可以看到在數(shù)據(jù)狀態(tài)協(xié)程之間互不影響。注意上面contextvars.ContextVar的傳入的第一個(gè)參數(shù)(name)值是一個(gè)字符串,它主要是用來標(biāo)識(shí)和調(diào)試的,并不一定要用一個(gè)單詞或者用下劃線連起來。

注意,這個(gè)模塊不僅僅給aio加入Context的支持,也用來替代threading.local()。

在Python 3.6使用contextvars

contextvars實(shí)現(xiàn)了PEP 567, 如果在Python3.6想使用可以用MagicStack/contextvars這個(gè)向后移植庫(kù),它和標(biāo)準(zhǔn)庫(kù)都是同一個(gè)作者寫的,可以放心使用。用之前你需要安裝它:

pip install contextvars
aiotask_context

在Sanic里面request確實(shí)沒有用Context,那在aio體系里面怎么用呢?原來我會(huì)使用一個(gè)獨(dú)立的庫(kù)aiotask_context,在我的技術(shù)博客項(xiàng)目中就有用到,我簡(jiǎn)化一下這部分的代碼(延伸閱讀3的commit):

# ext.py
import aiotask_context as context  # noqa
# app.py
from ext import context
client = None
@app.listener('before_server_start')
async def setup_db(app, loop):
    global client
    client = aiomcache.Client(config.MEMCACHED_HOST, config.MEMCACHED_PORT, loop=loop)
    loop.set_task_factory(context.task_factory)
@app.middleware('request')
async def setup_context(request):
    context.set('memcache', client)
# models/mc.py
_memcache = None
async def get_memcache():
    global _memcache
    if _memcache is not None:
        return _memcache
    memcache = context.get('memcache')
    _memcache = memcache
    return memcache

按執(zhí)行過程,我解釋一下:

app.py默認(rèn)client是None,在before_server_start中會(huì)設(shè)置初始化一個(gè)aiomcache.Client,用global設(shè)置給client

每次請(qǐng)求,通過context.set('memcache', client)把client設(shè)置到Context里面

在實(shí)際業(yè)務(wù)中,直接用context.get('memcache')獲取這個(gè)client。整個(gè)邏輯中見不到client傳來傳去,也不需要給request設(shè)置額外的屬性

有一點(diǎn)要提,在Python 3.6, context接受的參數(shù)必須是ContextVar對(duì)象,要這么寫:

if PY36:
    import contextvars
    memcache_var = contextvars.ContextVar('memcache')
else:
    memcache_var = 'memcache'
try:
    memcache = context.get(memcache_var)
except AttributeError:
    # Hack for debug mode
    memcache = None

這里捕獲了AttributeError,主要是在ipython中調(diào)試,由于沒有啟動(dòng)Sanic所以沒有設(shè)置上下文,所以需要異常處理一下。

contextvars的真實(shí)例子

接著替換成contextvars(延伸閱讀鏈接4的commit):

# models/var.py
import contextvars
memcache_var = contextvars.ContextVar('memcache')
# app.py
from models.var import memcache_var
client = None
@app.listener('before_server_start')
async def setup_db(app, loop):
    global client
    client = aiomcache.Client(config.MEMCACHED_HOST, config.MEMCACHED_PORT, loop=loop)
@app.middleware('request')
async def setup_context(request):
    memcache_var.set(client)
# models/mc.py
from models.var import memcache_var
_memcache = None
async def get_memcache():
    global _memcache
    if _memcache is not None:
        return _memcache
    memcache = memcache_var.get()
    _memcache = memcache
    return memcache

在這種模式下,memcache(Redis)等實(shí)例對(duì)象不需要放在request對(duì)象里面,也不需要傳來傳去,而是放在一個(gè)上下文中,需要時(shí)直接通過memcache_var.get()就可以拿到,繼而操作緩存了。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享Python3中contextvars模塊是什么內(nèi)容對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道,遇到問題就找創(chuàng)新互聯(lián),詳細(xì)的解決方法等著你來學(xué)習(xí)!

名稱欄目:Python3中contextvars模塊是什么-創(chuàng)新互聯(lián)
文章出自:http://aaarwkj.com/article42/cojdec.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、App開發(fā)、用戶體驗(yàn)、云服務(wù)器、網(wǎng)站收錄、App設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽(yáng)服務(wù)器托管
在线观看中文字幕一区| 欧美日韩一级一区二区| 欧美 日韩一区二区在线| 在线一区二区三区高清视频| 欧美精品国产一区二区免费| 国内精品人妻中文字幕| 成年人免费久久毛片| 熟妇人妻精品一区二区| 女性裸体无遮挡啪啪网站| 婷婷色悠悠,色悠悠激情啪啪| 国产精品一级片免费看| 欧美午夜一级特黄大片| 欧美口爆吞精在线观看| 国产精品一区在线播放| 白白色最新福利在线视频观看| 日韩欧美的一区二区三区| 亚洲av乱码一区二区三| 97成人在线视频免费播放| 国产剧情av一区在线观看| 一区二区日韩视频九一蜜桃| 好吊精品视频在线观看| 日韩精品免费一区二区三区| 欧美黑人在线一区二区| 91观看免费完整版高清| 麻豆视频传媒入口在线播放| 精品欧美熟妇高潮喷水特黄| 欧美二区三区精品在线| 精品中文字幕欧美区一区| 五月天久久开心激情网| 日本女人体内射精视频| 国产精品免费看片网站| 日韩精品一区伦理视频| 亚洲日本乱码一区二区三| 欧美一区二区三区高清在线| 91伊人手机在线观看| 亚洲欧美精品专区极品| 日韩在线一区二区三区电影 | 亚洲国产精品一区二区成人| 精品国产一区二区av麻豆| 精品亚洲国产一区二区三区| 粉嫩极品美女国产精品|