Flask 上下文源碼解析

簡單來說,上下文包括request_ctx(封裝了request和session),app_request(封裝了app和g),兩個ctx都儲存在一個叫做Local的數據結構中,這個結構的作用就是會自動根據不同的線程id返回對應的數據,然后通過一個叫做 LocalStark 的結構把 Local 封裝成棧,并提供pop和push 功能,request_ctx,app_request的入棧就是通過它實現,在程序中調用數據的時候,通過一個叫做LocalProxy的結構加上偏函數partial來獲取

上下文一直是計算機中難理解的概念,在知乎的一個問題下面有個很通俗易懂的回答:

每一段程序都有很多外部變量。只有像Add這種簡單的函數才是沒有外部變量的。一旦你的一段程序有了外部變量,這段程序就不完整,不能獨立運行。你為了使他們運行,就要給所有的外部變量一個一個寫一些值進去。這些值的集合就叫上下文。– vzch

比如,在 flask 中,視圖函數需要知道它執行情況的請求信息(請求的 url,參數,方法等)以及應用信息(應用中初始化的數據庫等),才能夠正確運行。最直觀地做法是把這些信息封裝成一個對象,作為參數傳遞給視圖函數。但是這樣的話,所有的視圖函數都需要添加對應的參數,即使該函數內部并沒有使用到它。

flask 的做法是把這些信息作為類似全局變量的東西,視圖函數需要的時候,可以使用?from flask import request?獲取。但是這些對象和全局變量不同的是——它們必須是動態的,因為在多線程或者多協程的情況下,每個線程或者協程獲取的都是自己獨特的對象,不會互相干擾。

那么如何實現這種效果呢?如果對 python 多線程比較熟悉的話,應該知道多線程中有個非常類似的概念?threading.local,可以實現多線程訪問某個變量的時候只看到自己的數據。內部的原理說起來也很簡單,這個對象有一個字典,保存了線程 id 對應的數據,讀取該對象的時候,它動態地查詢當前線程 id 對應的數據。flask python 上下文的實現也類似,后面會詳細解釋。

1、初步印象

flask 中有兩種上下文:application context?和?request context。上下文有關的內容定義在?globals.py?文件,文件的內容也非常短:

################################### globals.py ###################################
def _lookup_req_object(name):top = _request_ctx_stack.topif top is None:raise RuntimeError(_request_ctx_err_msg)return getattr(top, name)def _lookup_app_object(name):top = _app_ctx_stack.topif top is None:raise RuntimeError(_app_ctx_err_msg)return getattr(top, name)def _find_app():top = _app_ctx_stack.topif top is None:raise RuntimeError(_app_ctx_err_msg)return top.app# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

flask?提供兩種上下文:application context?和?request context?。app lication context?又演化出來兩個量?current_app?和?g,而?request context?則演化出來?request?和?session

這里的實現用到了兩個東西:LocalStack?和?LocalProxy。它們兩個的結果就是我們可以動態地獲取兩個上下文的內容,在并發程序中每個視圖函數都會看到屬于自己的上下文,而不會出現混亂。

2 存儲上下文,模擬local

LocalStack?和?LocalProxy?都是?werkzeug?提供的。在分析這兩個類之前,我們先介紹這個文件另外一個基礎的類?LocalLocal?就是實現了類似?threading.local?的效果,多線程或者多協程情況下全局變量的隔離效果。下面是它的代碼:

################################## local.py ###################################
# since each thread has its own greenlet we can just use those as identifiers
# for the context.  If greenlets are not available we fall back to the
# current thread ident depending on where it is.
try:from greenlet import getcurrent as get_ident
except ImportError:try:from thread import get_identexcept ImportError:from _thread import get_identclass Local(object):__slots__ = ('__storage__', '__ident_func__')def __init__(self):# 數據保存在 __storage__ 中,后續訪問都是對該屬性的操作# 因為還沒有實例化,所以不能調用自己的__setattr__object.__setattr__(self, '__storage__', {})object.__setattr__(self, '__ident_func__', get_ident)def __call__(self, proxy):"""Create a proxy for a name."""return LocalProxy(self, proxy)# 清空當前線程/協程保存的所有數據def __release_local__(self):self.__storage__.pop(self.__ident_func__(), None)# 下面三個方法實現了屬性的訪問、設置和刪除。# 注意到,內部都調用 `self.__ident_func__` 獲取當前線程或者協程的 id,然后再訪問對應的內部字典。# 如果訪問或者刪除的屬性不存在,會拋出 AttributeError。# 這樣,外部用戶看到的就是它在訪問實例的屬性,完全不知道字典或者多線程/協程切換的實現def __getattr__(self, name):try:return self.__storage__[self.__ident_func__()][name]except KeyError:raise AttributeError(name)def __setattr__(self, name, value):ident = self.__ident_func__()storage = self.__storage__try:storage[ident][name] = valueexcept KeyError:storage[ident] = {name: value}def __delattr__(self, name):try:del self.__storage__[self.__ident_func__()][name]except KeyError:raise AttributeError(name)

可以看到,Local?對象內部的數據都是保存在?__storage__?屬性的,這個屬性變量是個嵌套的字典:__storage__{ident:{key:value}}。最外面字典 key 是線程或者協程的 identity,value 是另外一個字典,這個內部字典就是用戶自定義的 key-value 鍵值對。用戶訪問實例的屬性,就變成了訪問內部的字典,外面字典的 key 是自動關聯的。__ident_func?是 協程的?get_current?或者線程的?get_ident,從而獲取當前代碼所在線程或者協程的 id。

除了這些基本操作之外,Local?還實現了?__release_local__?,用來清空(析構)當前線程或者協程的數據(狀態)。__call__?操作來創建一個?LocalProxy?對象,LocalProxy?會在下面講到。

3 操作 Local ,將Local維護成棧

理解了?Local,我們繼續回來看另外兩個類。

LocalStack?是基于?Local?實現的棧結構。如果說?Local?提供了多線程或者多協程隔離的屬性訪問,那么?LocalStack?就提供了隔離的棧訪問。下面是它的實現代碼,可以看到它提供了?pushpop?和?top?方法。

__release_local__?可以用來清空當前線程或者協程的棧數據,__call__?方法返回當前線程或者協程棧頂元素的代理對象。

################################## local.py ###################################
class LocalStack(object):"""This class works similar to a :class:`Local` but keeps a stackof objects instead. """def __init__(self):self._local = Local()def __release_local__(self):self._local.__release_local__()def __call__(self):def_lookup():rv = self.topif rv is None:raise RuntimeError('object unbound')return rvreturn LocalProxy(_lookup)# push、pop 和 top 三個方法實現了棧的操作,# 可以看到棧的數據是保存在 self._local.stack 屬性中的def push(self, obj):"""Pushes a new item to the stack"""rv = getattr(self._local, 'stack', None)if rv is None:self._local.stack = rv = []rv.append(obj)return rvdef pop(self):"""Removes the topmost item from the stack, will return theold value or `None` if the stack was already empty."""stack = getattr(self._local, 'stack', None)if stack is None:return Noneelif len(stack) == 1:release_local(self._local)  # 調用的local.py下的函數,實際執行local類下的__release__local__return stack[-1]else:return stack.pop()# 返回棧頂元素@propertydef top(self):"""The topmost item on the stack.  If the stack is empty,`None` is returned."""try:return self._local.stack[-1]except (AttributeError, IndexError):return None

我們在之前看到了?request context?的定義,它就是一個?LocalStack?的實例:

_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()

它會當前線程或者協程的請求都保存在棧里,等使用的時候再從里面讀取。至于為什么要用到棧結構,而不是直接使用?Local,我們會在后面揭曉答案,你可以先思考一下。

4、使用 代理LocalProxy 和 偏函數partial 獲取棧中數據

LocalProxy?是一個?Local?對象的代理,負責把所有對自己的操作轉發給內部的?Local?對象。LocalProxy?的構造函數介紹一個 callable 的參數,這個 callable 調用之后需要返回一個?Local?實例,后續所有的屬性操作都會轉發給 callable 返回的對象。

@implements_bool
class LocalProxy(object):"""Acts as a proxy for a werkzeug local.  Forwards all operations toa proxied object.  The only operations not supported for forwardingare right handed operands and any kind of assignment.Example usage::from werkzeug.local import Locall = Local()# these are proxiesrequest = l('request')user = l('user')from werkzeug.local import LocalStack_response_local = LocalStack()# this is a proxyresponse = _response_local()Whenever something is bound to l.user / l.request the proxy objectswill forward all operations.  If no object is bound a :exc:`RuntimeError`will be raised.To create proxies to :class:`Local` or :class:`LocalStack` objects,call the object as shown above.  If you want to have a proxy to anobject looked up by a function, you can (as of Werkzeug 0.6.1) passa function to the :class:`LocalProxy` constructor::session = LocalProxy(lambda: get_current_request().session).. versionchanged:: 0.6.1The class can be instantiated with a callable as well now."""__slots__ = ("__local", "__dict__", "__name__", "__wrapped__")def __init__(self, local, name=None):object.__setattr__(self, "_LocalProxy__local", local)object.__setattr__(self, "__name__", name)if callable(local) and not hasattr(local, "__release_local__"):# "local" is a callable that is not an instance of Local or# LocalManager: mark it as a wrapped function.object.__setattr__(self, "__wrapped__", local)def _get_current_object(self):"""Return the current object.  This is useful if you want the realobject behind the proxy at a time for performance reasons or becauseyou want to pass the object into a different context."""if not hasattr(self.__local, "__release_local__"):return self.__local()try:return getattr(self.__local, self.__name__)except AttributeError:raise RuntimeError("no object bound to %s" % self.__name__)@propertydef __dict__(self):try:return self._get_current_object().__dict__except RuntimeError:raise AttributeError("__dict__")def __repr__(self):try:obj = self._get_current_object()except RuntimeError:return "<%s unbound>" % self.__class__.__name__return repr(obj)def __bool__(self):try:return bool(self._get_current_object())except RuntimeError:return Falsedef __unicode__(self):try:return unicode(self._get_current_object())  # noqaexcept RuntimeError:return repr(self)def __dir__(self):try:return dir(self._get_current_object())except RuntimeError:return []def __getattr__(self, name):if name == "__members__":return dir(self._get_current_object())return getattr(self._get_current_object(), name)def __setitem__(self, key, value):self._get_current_object()[key] = valuedef __delitem__(self, key):del self._get_current_object()[key]if PY2:__getslice__ = lambda x, i, j: x._get_current_object()[i:j]def __setslice__(self, i, j, seq):self._get_current_object()[i:j] = seqdef __delslice__(self, i, j):del self._get_current_object()[i:j]__setattr__ = lambda x, n, v: setattr(x._get_current_object(), n, v)__delattr__ = lambda x, n: delattr(x._get_current_object(), n)__str__ = lambda x: str(x._get_current_object())__lt__ = lambda x, o: x._get_current_object() < o__le__ = lambda x, o: x._get_current_object() <= o__eq__ = lambda x, o: x._get_current_object() == o__ne__ = lambda x, o: x._get_current_object() != o__gt__ = lambda x, o: x._get_current_object() > o__ge__ = lambda x, o: x._get_current_object() >= o__cmp__ = lambda x, o: cmp(x._get_current_object(), o)  # noqa__hash__ = lambda x: hash(x._get_current_object())__call__ = lambda x, *a, **kw: x._get_current_object()(*a, **kw)__len__ = lambda x: len(x._get_current_object())__getitem__ = lambda x, i: x._get_current_object()[i]__iter__ = lambda x: iter(x._get_current_object())__contains__ = lambda x, i: i in x._get_current_object()__add__ = lambda x, o: x._get_current_object() + o__sub__ = lambda x, o: x._get_current_object() - o__mul__ = lambda x, o: x._get_current_object() * o__floordiv__ = lambda x, o: x._get_current_object() // o__mod__ = lambda x, o: x._get_current_object() % o__divmod__ = lambda x, o: x._get_current_object().__divmod__(o)__pow__ = lambda x, o: x._get_current_object() ** o__lshift__ = lambda x, o: x._get_current_object() << o__rshift__ = lambda x, o: x._get_current_object() >> o__and__ = lambda x, o: x._get_current_object() & o__xor__ = lambda x, o: x._get_current_object() ^ o__or__ = lambda x, o: x._get_current_object() | o__div__ = lambda x, o: x._get_current_object().__div__(o)__truediv__ = lambda x, o: x._get_current_object().__truediv__(o)__neg__ = lambda x: -(x._get_current_object())__pos__ = lambda x: +(x._get_current_object())__abs__ = lambda x: abs(x._get_current_object())__invert__ = lambda x: ~(x._get_current_object())__complex__ = lambda x: complex(x._get_current_object())__int__ = lambda x: int(x._get_current_object())__long__ = lambda x: long(x._get_current_object())  # noqa__float__ = lambda x: float(x._get_current_object())__oct__ = lambda x: oct(x._get_current_object())__hex__ = lambda x: hex(x._get_current_object())__index__ = lambda x: x._get_current_object().__index__()__coerce__ = lambda x, o: x._get_current_object().__coerce__(x, o)__enter__ = lambda x: x._get_current_object().__enter__()__exit__ = lambda x, *a, **kw: x._get_current_object().__exit__(*a, **kw)__radd__ = lambda x, o: o + x._get_current_object()__rsub__ = lambda x, o: o - x._get_current_object()__rmul__ = lambda x, o: o * x._get_current_object()__rdiv__ = lambda x, o: o / x._get_current_object()if PY2:__rtruediv__ = lambda x, o: x._get_current_object().__rtruediv__(o)else:__rtruediv__ = __rdiv____rfloordiv__ = lambda x, o: o // x._get_current_object()__rmod__ = lambda x, o: o % x._get_current_object()__rdivmod__ = lambda x, o: x._get_current_object().__rdivmod__(o)__copy__ = lambda x: copy.copy(x._get_current_object())__deepcopy__ = lambda x, memo: copy.deepcopy(x._get_current_object(), memo)

這里實現的關鍵是把通過參數傳遞進來的?Local?實例保存在?__local?屬性中,并定義了?_get_current_object()?方法獲取當前線程或者協程對應的對象。這里通過?“_LocalProxy__local”?設置的值,后面可以通過?self.__local?來獲取。

然后?LocalProxy?重寫了所有的魔術方法(名字前后有兩個下劃線的方法),具體操作都是轉發給代理對象的。繼續回到?request context?的實現:

_request_ctx_stack = LocalStack()
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))

再次看這段代碼希望能看明白,_request_ctx_stack?是多線程或者協程隔離的棧結構,request?每次都會用?_lookup_req_object?棧頭部的數據來獲取保存在里面的?requst context

上下文流程

那么請求上下文信息是什么被放在 stack 中呢?還記得之前介紹的?wsgi_app()?方法有下面兩行代碼嗎?,具體可參考Falsk session 源碼解析

ctx = self.request_context(environ)
ctx.push()

每次在調用?app.__call__?的時候,都會把對應的請求信息壓棧,最后執行完請求的處理之后把它出棧。先來看看request_context, 這個 方法只有一行代碼:

def request_context(self, environ):return RequestContext(self, environ)

它調用了?RequestContext,并把?self?和請求信息的字典?environ?當做參數傳遞進去。追蹤到?RequestContext?定義的地方,它出現在?ctx.py?文件中,代碼如下:

class RequestContext(object):"""The request context contains all request relevant information.  It iscreated at the beginning of the request and pushed to the`_request_ctx_stack` and removed at the end of it.  It will create theURL adapter and request object for the WSGI environment provided."""def __init__(self, app, environ, request=None):self.app = app# 對environ進行第二次封裝,封裝成一個Request對象if request is None:request = app.request_class(environ)  #?request_class = Request ?實際執行為 request = Request(environ)self.request = requestself.url_adapter = app.create_url_adapter(self.request)self.flashes = None# 為session 賦值 Noneself.session = Noneself._implicit_app_ctx_stack = []self.preserved = Falseself._preserved_exc = Noneself._after_request_functions = []self.match_request()def match_request(self):"""Can be overridden by a subclass to hook into the matchingof the request."""try:url_rule, self.request.view_args = \self.url_adapter.match(return_rule=True)self.request.url_rule = url_ruleexcept HTTPException as e:self.request.routing_exception = edef push(self):"""Binds the request context to the current context."""# If an exception occurs in debug mode or if context preservation is# activated under exception situations exactly one context stays# on the stack.  The rationale is that you want to access that# information under debug situations.  However if someone forgets to# pop that context again we want to make sure that on the next push# it's invalidated, otherwise we run at risk that something leaks# memory.  This is usually only a problem in test suite since this# functionality is not active in production environments.top = _request_ctx_stack.topif top is not None and top.preserved:top.pop(top._preserved_exc)# Before we push the request context we have to ensure that there# is an application context.app_ctx = _app_ctx_stack.topif app_ctx is None or app_ctx.app != self.app:app_ctx = self.app.app_context()app_ctx.push()self._implicit_app_ctx_stack.append(app_ctx)else:self._implicit_app_ctx_stack.append(None)if hasattr(sys, "exc_clear"):sys.exc_clear()_request_ctx_stack.push(self)# Open the session at the moment that the request context is available.# This allows a custom open_session method to use the request context.# Only open a new session if this is the first time the request was# pushed, otherwise stream_with_context loses the session.if self.session is None:session_interface = self.app.session_interfaceself.session = session_interface.open_session(self.app, self.request)if self.session is None:self.session = session_interface.make_null_session(self.app)if self.url_adapter is not None:self.match_request()def pop(self, exc=_sentinel):"""Pops the request context and unbinds it by doing that.  This willalso trigger the execution of functions registered by the:meth:`~flask.Flask.teardown_request` decorator... versionchanged:: 0.9Added the `exc` argument."""app_ctx = self._implicit_app_ctx_stack.pop()try:clear_request = Falseif not self._implicit_app_ctx_stack:self.preserved = Falseself._preserved_exc = Noneif exc is _sentinel:exc = sys.exc_info()[1]self.app.do_teardown_request(exc)# If this interpreter supports clearing the exception information# we do that now.  This will only go into effect on Python 2.x,# on 3.x it disappears automatically at the end of the exception# stack.if hasattr(sys, "exc_clear"):sys.exc_clear()request_close = getattr(self.request, "close", None)if request_close is not None:request_close()clear_request = Truefinally:rv = _request_ctx_stack.pop()# get rid of circular dependencies at the end of the request# so that we don't require the GC to be active.if clear_request:rv.request.environ["werkzeug.request"] = None# Get rid of the app as well if necessary.if app_ctx is not None:app_ctx.pop(exc)assert rv is self, "Popped wrong request context. (%r instead of %r)" % (rv,self,)def auto_pop(self, exc):if self.request.environ.get("flask._preserve_context") or (exc is not None and self.app.preserve_context_on_exception):self.preserved = Trueself._preserved_exc = excelse:self.pop(exc)def __enter__(self):self.push()return selfdef __exit__(self, exc_type, exc_value, tb):# do not pop the request stack if we are in debug mode and an# exception happened.  This will allow the debugger to still# access the request object in the interactive shell.  Furthermore# the context can be force kept alive for the test client.# See flask.testing for how this works.self.auto_pop(exc_value)if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:reraise(exc_type, exc_value, tb)def __repr__(self):return "<%s '%s' [%s] of %s>" % (self.__class__.__name__,self.request.url,self.request.method,self.app.name,)

每個 request context 都保存了當前請求的信息,比如 request 對象和 app 對象。在初始化的最后,還調用了?match_request?實現了路由的匹配邏輯。

push?操作就是把該請求的?ApplicationContext(如果?_app_ctx_stack?棧頂不是當前請求所在 app ,需要創建新的 app context) 和?RequestContext?有關的信息保存到對應的棧上,壓棧后還會保存 session 的信息;?pop?則相反,把 request context 和 application context 出棧,做一些清理性的工作。

到這里,上下文的實現就比較清晰了:每次有請求過來的時候,flask 會先創建當前線程或者進程需要處理的兩個重要上下文對象,把它們保存到隔離的棧里面,這樣視圖函數進行處理的時候就能直接從棧上獲取這些信息。

NOTE:因為 app 實例只有一個,因此多個?request?共享了?application context

為什么使用兩個上下文

  1. 為什么要把 request context 和 application context 分開?每個請求不是都同時擁有這兩個上下文信息嗎?
  2. 為什么 request context 和 application context 都有實現成棧的結構?每個請求難道會出現多個 request context 或者 application context 嗎?

第一個答案是“靈活度”,第二個答案是“多 application”。雖然在實際運行中,每個請求對應一個 request context 和一個 application context,但是在測試或者 python shell 中運行的時候,用戶可以單獨創建 request context 或者 application context,這種靈活度方便用戶的不同的使用場景(比如沒有請求的時候,創建數據庫需要調用app以便了解數據的鏈接信息);而且棧可以讓 redirect 更容易實現,一個處理函數可以從棧中獲取重定向路徑的多個請求信息。application 設計成棧也是類似,測試的時候可以添加多個上下文,另外一個原因是 flask 可以多個 application 同時運行:

from werkzeug.wsgi import DispatcherMiddleware
from frontend_app import application as frontend
from backend_app import application as backendapplication = DispatcherMiddleware(frontend, {'/backend':     backend
})

這個例子就是使用?werkzeug?的?DispatcherMiddleware?實現多個 app 的分發,這種情況下?_app_ctx_stack?棧里會出現兩個 application context。

為什么要用 LocalProxy

為什么要使用?LocalProxy?不使用?LocalProxy?直接訪問?LocalStack?的對象會有什么問題嗎?

首先明確一點,Local?和?LocalStack?實現了不同線程/協程之間的數據隔離。在為什么用?LocalStack?而不是直接使用?Local?的時候,我們說過這是因為 flask 希望在測試或者開發的時候,允許多 app 、多 request 的情況。而?LocalProxy?也是因為這個才引入進來的!

我們拿?current_app = LocalProxy(_find_app)?來舉例子。每次使用?current_app?的時候,他都會調用?_find_app?函數,然后對得到的變量進行操作。

如果直接使用?current_app = _find_app()?有什么區別呢?區別就在于,我們導入進來之后,current_app?就不會再變化了。如果有多 app 的情況,就會出現錯誤,比如:

from flask import current_appapp = create_app()
admin_app = create_admin_app()def do_something():with app.app_context():work_on(current_app)with admin_app.app_context():work_on(current_app)

這里我們出現了嵌套的 app,每個 with 上下文都需要操作其對應的?app,如果不適用?LocalProxy?是做不到的。

對于?request?也是類似!但是這種情況真的很少發生,有必要費這么大的功夫增加這么多復雜度嗎?

其實還有一個更大的問題,這個例子也可以看出來。比如我們知道?current_app?是動態的,因為它背后對應的棧會 push 和 pop 元素進去。那剛開始的時候,棧一定是空的,只有在?with app.app_context()?這句的時候,才把棧數據 push 進去。而如果不采用LocalProxy進行轉發,那么在最上面導入?from flask import current_app?的時候,current_app?就是空的,因為這個時候還沒有把數據 push 進去,后面調用的時候根本無法使用。

所以為什么需要?LocalProxy?呢?簡單總結一句話:因為上下文保存的數據是保存在棧里的,并且會動態發生變化。如果不是動態地去訪問,會造成數據訪問異常。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/454101.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454101.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454101.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

reg型變量怎么賦值_UiPath變量介紹和使用

1 變量變量主要用于存儲數據&#xff0c;它在RPA中扮演重要的數據傳遞角色&#xff0c;是RPA編程不可或缺的一部分。它包括變量名稱和變量的值&#xff0c;變量的值支持多種數據類型&#xff0c;包括從通用值&#xff0c;文本&#xff0c;數字&#xff0c;數據表&#xff0c;時…

gcc 使用教程

gcc 使用教程 目 錄 gcc makefile寫法 gcc_egcs使用 gdb使用 gcc常用選項對代碼的影響 一般情況 -O 編譯選項 -O2 編譯選項 -fomit-frame-pointer 編譯選項-fomit-frame-pointer && -O2-fPIC 編譯選項 -static 編譯選項 AT&T的匯編格式 x86內聯匯編 簡述 內聯匯編…

Struts2教程9:實現自已的攔截器

在上一篇中介紹了Struts2攔截器的原理&#xff0c;在這一篇中我們將學習一下如何編寫自己的攔截器。一、攔截器的實現實現一個攔截器非常簡單。實際上&#xff0c;一個攔截器就是一個普通的類&#xff0c;只是這個類必須實現com.opensymphony.xwork2.interceptor.Interceptor接…

標準C程序設計七---66

Linux應用 編程深入 語言編程標準C程序設計七---經典C11程序設計 以下內容為閱讀&#xff1a; 《標準C程序設計》&#xff08;第7版&#xff09; 作者&#xff1a;E. Balagurusamy&#xff08;印&#xff09;&#xff0c; 李周芳譯 清華大學出版社…

深度學習之概述

深度學習的應用場景 1、圖像應用&#xff1a; 1.1 大規模(大數據量)圖片識別(聚類/分類)&#xff0c;如人臉識別&#xff0c;車牌識別&#xff0c;OCR等。人臉識別算法&#xff1a;① faceID ② faceNet 1.2 以圖搜圖&#xff0c;圖像分割 1.3 目標檢測&#xff0…

如何根據對象獲取到對應的表名_Excel VBA 常用對象二

下面繼續講解上一節中未講完的內容&#xff1a;Excel VBA編程中常常使用的那些對象到底是什么&#xff0c;如何在代碼中表示它們。Worksheet對象Worksheet對象代表工作表。工作簿中的每個工作表都是一個Worksheet對象&#xff0c;所有Worksheet對象構成了Worksheets集合。我們使…

PIX525故障一例,求解

IDC機房網絡拓樸如下&#xff1a;IDC核心交換機-----通過一條網線-------機柜D-LNKI交換機------PIX 525------CISCO交換機------各WEB服務器。其中D-LINK交換機的IP為192.168.2.11&#xff0c;也就是下面日志中的IP。另外&#xff0c;之所以IDC和PIX之間再加一臺DLINK是因為有…

gcc教程(轉)

gcc 目 錄 gcc makefile寫法 gcc_egcs使用 gdb使用 gcc常用選項對代碼的影響 一般情況 -O 編譯選項 -O2 編譯選項 -fomit-frame-pointer 編譯選項 -fomit-frame-pointer && -O2 -fPIC 編譯選項 -static 編譯選項 AT&T的匯編格式 x86內聯匯編 簡述 內聯匯編 程序模…

深度學習之 BP 算法

神經網絡的一種求解W的算法&#xff0c;分為信號“正向傳播(FP)”求損失&#xff0c;“反向傳播(BP)”回傳誤差&#xff1b;根據誤差值修改每層的權重&#xff0c;繼續迭代。 BP算法也叫做δ算法。以三層的感知器為例&#xff08;假定現在隱層和輸出層均存在相同類型的激活函數…

python自帶的解釋器叫做_python學習

一、PYTHON中的元素1.基本元素運算符&#xff1a; - * / %等等除法&#xff1a;" / " 表示浮點數除法&#xff0c;返回浮點結果;" // " 表示整數除法,返回不大于結果的一個最大的整數運算順序&#xff1a;先乘除 再加減 括號最優先變量&#xff1a;就是一…

IE打印空白

今天碰到HR經理碰到一個問題&#xff0c;就是windows 7 64位操作系統&#xff0c;但是打印空白&#xff0c;打印出來像白紙一樣&#xff01;經過查看和總結&#xff0c;確認是&#xff1a;由于保護模式下 %Temp%\Low 文件夾工作不正常引起的&#xff01;故障打印白紙下面會出現…

Python Matplotlib.plot Update image Questions

1. 最近在測試一款設備&#xff0c;采集了一些設備后需要一幀一幀顯示圖像&#xff0c;經常使用Python,所以選用了Matplotlib進行圖像操作 數據結構&#xff1a; timesatamp polar_distance horizontal_angle refelectivity_intensity,所有數據類型都是 float&#xff0c;儲存在…

深度學習之 RBF神經網絡

RBF神經網絡通常只有三層&#xff0c;即輸入層、中間層和輸出層。其中中間層主要計算輸入x和樣本矢量c&#xff08;記憶樣本&#xff09;之間的歐式距離的Radial Basis Function (RBF)的值&#xff0c;輸出層對其做一個線性的組合。 徑向基函數&#xff1a; RBF神經網絡的訓練…

redis 隊列_Redis與Rabbitmq消息隊列的區別

將redis發布訂閱模式用做消息隊列和rabbitmq的區別&#xff1a;可靠性 redis &#xff1a;沒有相應的機制保證消息的可靠消費&#xff0c;如果發布者發布一條消息&#xff0c;而沒有對應的訂閱者的話&#xff0c;這條消息將丟失&#xff0c;不會存在內存中&#xff1b;rabbit…

EasyUI中那些不容易被發現的坑——EasyUI重復請求2次的問題

問題控件&#xff1a;datagrid、combobox、所有能設置url屬性的控件 問題版本&#xff1a;1.4.4、1.4.5&#xff08;之前的版本沒測&#xff09; 問題如圖&#xff1a; 重復請求2次&#xff0c;錯誤代碼如圖&#xff1a; 錯誤問題分析&#xff1a;html加載的時候回請求url加載數…

GCC編譯的背后( 預處理和編譯 匯編和鏈接 )

發表于 2010年05月18日 22:01 分類: 編程coding統計: 1評/465閱 2人收藏此文章&#xff0c; 收藏此文章(?)by falcon<zhangjinwgmail.com> 2008-02-22 平時在Linux下寫代碼&#xff0c;直接用"gcc -o out in.c"就把代碼編譯好了&#xff0c;但是這后面到底做了…

ElasticSearch Java API

ElasticSearch-Java Client類型 ElasticSearch-TransportClient環境準備 ElasticSearch-TransportClient連接 ElasticSearch-Document APIs ElasticSearch-搜索-原理 ElasticSearch-搜索-問題 ElasticSearch-搜索-問題解決思路 ElasticSearch-搜索-SearchType-類型一 E…

深度學習之卷積神經網絡(Convolutional Neural Networks, CNN)

前面, 介紹了DNN及其參數求解的方法(深度學習之 BP 算法),我們知道DNN仍然存在很多的問題&#xff0c;其中最主要的就是BP求解可能造成的梯度消失和梯度爆炸.那么,人們又是怎么解決這個問題的呢?本節的卷積神經網絡(Convolutional Neural Networks, CNN)就是一種解決方法. 我們…

Oracle DBA課程系列筆記(16)

第十六章&#xff1a; 用戶管理 1、schema &#xff1a; user.object &#xff0c;用戶認證方式&#xff1a;os 認證&#xff0c;database 認證 2、建立 database認證的用戶&#xff1a; 10:00:48 SQL> create user rose …

python序列是幾維_從一個1維的位數組獲得一個特定的2維的1序列數組[Python] - python...

我正在使用Python&#xff0c;我需要找到執行以下任務的最有效方法。任務&#xff1a;給定零和一的任何一維數組v&#xff0c;用k> 0表示v的所有一維的子序列數。我需要從v獲得一個二維數組w&#xff0c;使得&#xff1a;1)shape(w)(k&#xff0c;len(v))&#xff0c;2)對于…