Python非同步併發框架
呵呵,這個標題有點大,其實只是想從零開始介紹一下非同步的基礎,以及 Python 開源非同步併發框架的發展和互操作性。
另外,這是我在 OSTC 2014 做的一個同題演講,幻燈片在這裡,歡迎拍磚。
開源
Python 是開源的,介紹的這幾個框架 Twisted、Tornado、Gevent 和 tulip 也都是開源的,最後這個演講是在開源大會弄的,所以標題裡肯定少不了開源。另外,我的 gevent3 專案也是開源的——貌似不少同學被我起的極品名字給搞混了,特別說明一下,gevent3 雖然有跟 Gevent 一樣的介面外貌,但底層卻是 tulip 驅動的(考慮把名字改回
gulip 之類的);請區別於將來會支援 Python 3 的
非阻塞
先上一段程式碼。請原諒我用 Python 程式碼充當虛擬碼了,但 Python 的語法實在是太簡單了,忍不住啊。
import socket
s = socket.socket()
s.connect(('www.google.com', 80))
print("We are connected to %s:%d" % s.getpeername())
這是很簡單的一個客戶端 TCP 連線程式。假如網路狀況不是很好,執行這段程式時,我們很有可能要等個幾秒鐘,才能看到 We
are connected
的輸出字樣。
對於這樣的程式碼,我們就可以說程式阻塞在了 connect()
那麼非阻塞呢?還是看一段程式碼。
import socket
s = socket.socket()
s.setblocking(0)
try:
s.connect(('www.google.com', 80))
except socket.error as e:
print(str(e))
i = 0
while True:
try:
print("We are connected to %s:%d" % s.getpeername())
break
except:
print ("Let's do some math while waiting: %d" % i)
i += 1
else:
print("We are connected to %s:%d" % s.getpeername())
這一下程式碼就多了——但是並不複雜。
首先看一開始的變化,多了一句 s.setblocking(0)
。這是說,將這個
socket 物件變成非阻塞式的。這樣一來,接下來的許多本應阻塞的呼叫將不會阻塞。
比如 connect()
。非阻塞的 connect()
呼叫將會立即結束,而不管這個
TCP 連線是否真正建立了——如果 TCP 連線還沒有完成握手,那麼 connect()
會丟擲一個異常說“開始連了,彆著急一會兒就好”;否則(應該沒有否則)就會“正常”地走 try...else
的路線。
抓到這個異常之後呢,我們就可以充分利用這段原本要阻塞的時間,在連線完全建立之前做一些有意義的事情——比如數數。我這裡網路條件還湊合,一般情況下數到一萬多的時候就能跟 Google 連上了。
非同步
可以看得出來,阻塞和非阻塞是說函式呼叫的,呼叫了之後要等到底層完事兒了之後才能繼續的叫做阻塞;呼叫了之後,要麼立即返回,要麼立即拋異常,這就是非阻塞。
而與之如影隨行的一對兒概念——同步和非同步——則說的是一段程式的執行處理方式。一般情況下,阻塞式的呼叫都可以叫做同步,但非阻塞式的呼叫不一定是非同步的。怎麼講呢,我們還是來看幾個例子。
while server.running:
request = server.receive()
response = handle(request)
server.send(response)
這片程式碼片段示意的是同步的處理方式。可以看得出來,接收請求、處理請求、傳送響應依次執行,前一個任務完成了才會做下一個;最外面還有一個 while
迴圈,使之不斷地收請求發響應,且是傳送完上一個響應之後才會接收下一個請求。請注意,我們並沒有看到 receive()
等函式的實現細節,他們在底層可以是阻塞的,也可以是非阻塞的,這都不會影響我們看到的這片程式碼片段是同步的。
那麼非同步的程式碼看上去是什麼樣的呢?請允許我用 Twisted 風格的程式碼來展示,因為非同步的程式碼太“扭曲”了:
while server.running:
deferred = server.receive()
deferred.addCallback(on_request)
def on_request(request):
deferred = handle(request)
deferred.addCallback(on_response)
def on_response(response):
server.send(response)
讓我來大概地解釋一下。為了實現非同步,這裡的 receive()
和 handle()
都必須是非阻塞的。在 Twisted 中非阻塞的函式會立即返回一個 Deferred 物件,通過給 Deferred 物件添加回調函式,我們可以實現在這件事情真正完成之後,執行回撥函式中定義的接下來要做的事兒。
看到扭曲的程度了吧。先接收一個請求——等等,你不一定立即就能接收到。好吧,等到接收到了的時候(on_request
),我們把這個請求送去處理,然後——等等,處理不一定馬上能完成。那好吧,等到處理完成之後(on_response
),我們再把這個響應傳送回去。說實話,我沒忍心寫,其實發送也不會立即完成……
雖然上面這段程式碼示例有些過份,仍有一些可以變得更簡潔的地方,但是這對於大型專案中非同步程式碼的描述並不失真。難道用所謂的非同步框架寫程式碼都會是這麼扭曲麼?
前面我們說的非同步只是非同步編碼——從編寫程式碼的方式上來判斷。而通常說的非同步框架,往往還會展現給使用者一些同步的介面(後面還會提到),在框架內部,這些介面也都是用非阻塞的非同步程式碼來實現的。對於這樣的框架,我們仍然叫他們非同步框架——總不能叫非阻塞框架,或是同步框架吧。
另外,非同步編碼也不一定就非要扭曲人性,還是有很多專案可以簡潔明瞭地編寫非同步程式碼的,只不過對於程式設計師的要求會比編寫同步程式碼稍高一些罷了。
併發與並行
好了,讓我們先把糾結的非同步放下,來看看另外兩個容易混淆的概念。
估計您已經從視訊裡聽了我辦港澳通行證的慘痛經歷了,這裡就不重複了,但仍然用這個例子來解釋一下併發和並行的概念吧。
並行的概念著重於處理端,也就是辦理通行證的工作人員。有 5 個視窗開放,就意味著同一時間可以有 5 個業務可以得到並行的處理。對於計算機來說,並行勢必要有多顆處理器,真正從物理上可以並行地處理多個任務;單 CPU 用多執行緒實現的叫做時分複用——也許超執行緒除外。
相對於並行著重於處理端,併發的概念則是關於請求端,也就是關於使用者的。當我們談及朝陽區出入境辦證大廳的併發量的時候,我們是在說該大廳在某一時刻能容納的前來辦證的人數,最大併發量說白了就是大廳裡能站下多少人——包括正在辦的和排隊的。
包括排隊的?那往大廳外面使勁兒排唄,這併發量豈不是無限大了?
與併發一起的還有很重要的一個概念,就是處理時間。如果一味追求併發量,勢必會導致處理時間的大幅上升,大量請求多半時間在排隊,這樣並不能算是一個高效的系統設計。所以在系統資源到達瓶頸的時候,也許限制併發量,拒絕一些請求也許是一個明智的選擇。
併發並不是不關心處理端,只不過多核並行或者單核時分複用都能實現併發,而且在實踐中這兩種實現方法往往會同時使用。多核並行實現的併發,其任務排程主要由作業系統完成,我們接下來著重關心一下單執行緒併發的任務排程問題。
事件驅動的單執行緒併發
只有一個執行緒,用阻塞呼叫是肯定無法實現併發的——除非把每次僅服務一個客戶叫做“併發量為 1 的併發”。所以,我們必然會用到非阻塞呼叫。
請回憶一下前面我們演示非阻塞呼叫的那個例子,我們在等待連線建立的過程中,做了一些其他的有意義的事情,一旦連線建立成功,我們會接著之前做一些關於連線的事情——輸出對方的地址。現在我們試著擴充套件這個例子,實現併發連線——我們同時啟動 100 個 TCP 連線,任何一個連線成功了就立即輸出對方地址。一開始我們可以這麼寫:
import socket
sockets = {}
for i in range(100):
s = socket.socket()
sockets[s.fileno()] = s
s.setblocking(0)
try:
s.connect(('www.google.com', 80))
except:
pass
我們將這 100 個 socket 物件按照他們的檔案描述符儲存在了一個叫做 sockets
的字典裡,並且一一呼叫了非阻塞的 connect()
函式。
可是,接下來怎麼寫呢?難道要重複呼叫每一個 socket 物件的 getpeername()
函式,直到他們都正確返回了為止?CPU
消耗太大了吧。
作業系統給我們提供了一些介面,專門用於這類問題的:select 及其升級版 epoll(Linux) 和 kqueue(*BSD 和 Mac OS X),他們通常也被統稱為 select 函式。select 是一種阻塞呼叫,專門用於從一些檔案描述符中,選出那些有新事件到達的描述符,其中事件包括可讀、可寫和出錯。換句話講呢,就是監視給出的 socket,任何一個有動靜了就立即返回有動靜的描述符。
比如前面這個例子裡,我們希望在任何一個連線成功建立的時候,輸出該連線的目的地址。於是接下來就可以這麼寫:
import select
while sockets:
fds = select.select([], list(sockets.keys()), [])[1]
for fd in fds:
s = sockets.pop(fd)
print("%d connected to %s:%d" % ((fd,) + s.getpeername()))
也就是說,每次迴圈,我們都會從剩餘的連線中,選出一些可寫的 socket 物件——那意味著連線已經成功建立了,然後將他們的目標地址輸出出來。
這就是一個很簡單的事件驅動的非同步併發了,雖然我們只是建立了 100 個 TCP 連線,但我們併發了,是事件驅動的了,而且我們非同步地呼叫了後續的操作——輸出目的地址。
非同步併發不過如此,而已。
框架
只用 socket
和 select
來寫一個非同步
web 伺服器也行,只不過會出一兩條人命而已。雖然是開玩笑,但是我們多數情況下還是會選擇使用一些現有的框架。
何謂框架呢,其實就是把上一小節的例子程式碼給拆開,一部分是僅包含 www.google.com
和 print()
的所謂使用者程式碼,另一部分就是所有剩下的叫做框架的東西。比如這樣:
import socket
sockets = {}
for i in range( ):
s =
sockets[s.fileno()] = s
s.setblocking(0)
try:
s. ( )
except:
pass
import select
while sockets:
fds = select.select([], list(sockets.keys()), [])[ ]
for fd in fds:
s = sockets.pop(fd)
( s. )
當然這段程式碼並不是一個框架,因為它根本無法執行。但是我們可以通過它看到一個非同步框架應該有的東西:
- 用於建立與框架契合的、非阻塞的 I/O 物件的介面
- 有一個主迴圈,使用者可以啟動它
- 使用者可以在關心的事件發生時,執行自己的程式碼
回撥函式和 Tornado
讓我們以 Tornado 為例,來看一下最基本的非同步框架是怎麼用的——雖然 Tornado 並不僅限於此。
sock = socket.socket()
sock.setblocking(0)
sock.bind((“”, 80))
sock.listen(128)
def on_conn(fd, events):
conn, address = sock.accept()
conn.send(b’Hello’)
io_loop = ioloop.IOLoop.instance()
io_loop.add_handler(sock.fileno(), on_conn, io_loop.READ)
io_loop.start()
這是一個簡單的伺服器程式,它會向每一個連進來的客戶端傳送一句問候。其中 add_handler()
的呼叫就是——我認為—— Tornado 的經典用法,也就是註冊回撥函式。當有連線進來的時候,Tornado 就會根據要求來呼叫 on_conn()
,後者隨即會與客戶端連線並送上問候。
Twisted 和封裝……和回撥函式
Twisted 裡是各種封裝,通過 Transport
將
socket 物件封裝的更隱蔽,通過 Protocol
來實現使用者協議的封裝,像這樣:
from twisted.internet import protocol, reactor
class Echo(protocol.Protocol):
def dataReceived(self, data):
self.transport.write(data)
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
return Echo()
reactor.listenTCP(1234, EchoFactory())
reactor.run()
對於回撥函式,Twisted 則發明了著名的 Deferred 用以實現事件源與回撥函式的分離,其實本質上沒有區別,只是在寫法上略有不同,這裡就不多說了。
同步地非同步
正如前面提到的,非同步的編碼方式——無論是 Tornado 的回撥函式,還是 Twisted 的 Deferred——想要用的出彩,需要程式設計師有相對較高的心理素質和職業修養。那如果能正常地、用同步的方式來編寫非同步執行的程式碼呢?
藉助 Python 的 generator
功能,Twisted 和 Tornado 紛紛提供了這樣的功能。比如下面這一段 Twisted 的程式碼(請關注開頭的修飾器和程式碼中的 yield
):
@defer.inlineCallbacks
def main(endpoint, username="alice", password=“secret”):
endpoint = endpoints.clientFromString(reactor, strport)
factory = protocol.Factory()
factory.protocol = imap4.IMAP4Client
try:
client = yield endpoint.connect(factory)
yield client.login(username, password)
yield client.select('INBOX')
info = yield client.fetchEnvelope(imap4.MessageSet(1))
print 'First message subject:', info[1]['ENVELOPE'][1]
except:
print "IMAP4 client interaction failed"
failure.Failure().printTraceback()
task.react(main, sys.argv[1:])
這裡的第一個 yield
中,endpoint.connect()
返回的是一個 Deferred 物件,其回撥函式的引數才是前面的 client
物件。通過 yield
跟 inlineCallbacks
修飾器的配合,我們就把回撥函式和 main
函式揉在了一起,後面那三個 yield
也是如此,這樣的程式碼看上去是同步的,執行的底層實則是非同步的。Tornado 也有類似的用法,這裡就不多說了。
神奇的 yield
!在這裡到底發生了什麼事情呢?我管它叫做非同步切換,具體的程式碼可以看 inlineCallbacks
的實現。簡單來說呢,yield
之前,connect()
在主迴圈裡註冊了一個關於連線創立的事件監聽,然後通過 yield
把事件的處理權交給了 inlineCallbacks
,同時將當前函式的執行狀態掛起(yield
的功能,可以把棧儲存下來),切換到 inlineCallbaks
裡繼續執行,而 inlineCallbacks
則會返回至主迴圈,繼續執行別的非同步任務,直至前述事件發生且主迴圈排到了該事件,主迴圈會呼叫 inlineCallbacks
裡的回撥函式,後者會將之前掛起的執行狀態恢復,這樣 client
就被賦上了正確的值。
總的來看,在 yield
的時候,當前執行流程會被暫停以等待事件,別的執行流程會插進來執行,直至事件發生後,當前執行流程才有可能恢復執行。這非常類似於作業系統裡面的任務排程,所以我管它叫做非同步切換,只不過這種切換是主動進行的,而不是作業系統強制的。所以,如果你不 yield
交出執行權,別的執行流程永遠沒有辦法被執行到,這也是單執行緒非同步併發的一個需要注意的點。另外,單執行緒非同步併發需要有足夠的非同步切換才能做到近似公平的排程,所以非常適合 I/O
密集型的運算,而 CPU 密集型的運算在這裡往往會遇到比較嚴重的問題。
隱式的非同步切換
在寫單執行緒非同步程式碼的時候,切記不要混合呼叫底層會阻塞的程式碼,因為那樣會阻塞整個執行緒,導致所有併發的處理時間增加,最終會導致嚴重的效能問題。如果有一些阻塞的、同步的遺留程式碼,那該如何是好呢?答案是:把它們統一改成非阻塞的,或者使用多執行緒/多程序來處理。可是,如果要改成非阻塞的形式,那得加多少 yield
呀!
沒關係,還有隱式的非同步切換呢。通常我們把這種需要顯式地寫 yield
的程式碼叫做顯式的非同步切換,與之相對的就是隱式的非同步切換。比如下面這段程式碼,我說它有隱式的非同步切換,您信嗎?
import socket
s = socket.socket()
s.connect(('www.google.com', 80))
print("We are connected to %s:%d" % s.getpeername())
這不就是文章一開頭的那個例子嘛。別急,如果在最前面加這麼兩句,情況就完全不一樣了:
from gevent import monkey
monkey.patch_all()
Gevent 就是隱式的非同步切換的代表。通過所謂的 monkey patch,Gevent 把系統庫裡的 socket
等模組,替換成了 Gevent 自己提供的相應的非阻塞模組。這樣,上面的程式碼就變成(底層)非同步的了。考慮到
monkey patch 的侵入性,您也可以考慮直接使用 Gevent提供的模組,比如這樣:
from gevent import socket
如 Gevent 這樣的隱式的非同步切換有個好處很明顯,就是可以很容易地將阻塞式的遺留程式碼遷移到 Gevent 上來,而不需要額外修改大量程式碼,這對於需要非同步併發支援的許多大型現有專案來說,無疑是為數不多的幾個選擇之一——比如說 Django。
但是,有不少人也認為,隱式的非同步切換的代價太大——倒不是說它的效能有多差,而是這種寫法把非同步切換隱藏的太深了,不知道什麼時候就切換到別的地方去執行了。這樣帶來的直接問題就是——跟常規共享狀態的多執行緒程式設計一樣——我們很難保證在一段程式的執行過程中,某些本地狀態不會被別的程式碼修改,再加上狀態同步的代價,隱式的非同步切換並不被特別看好。如果非得要用,記得儘量少共享狀態,多用佇列來實現資訊傳遞,然後小心編碼,仔細檢查。
綠色的 Gevent
Gevent 之所以能實現隱式的非同步切換,主要歸功於 Greenlet。Greenlet 是 Stackless Python 的一個分專案,用於在標準 CPython 中實現微執行緒(也稱協程、綠色執行緒)。
Python 中的 Greenlet 跟常規執行緒類似,也是會在獨立的空間中執行一段程式碼,也有自己獨立的棧空間。不同的是:
用官方的一個例子演示一下這兩個特點吧:
from greenlet import greenlet
def test1():
print 12
gr2.switch()
print 34
def test2():
print 56
gr1.switch()
print 78
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
這個例子裡一共有三個微執行緒,分別是 main(也就是最外層預設的主微執行緒,自動建立的)、gr1
和 gr2
。程式一直順序執行,直至最後一句 gr1.switch()
,由
main 微執行緒切換至 gr1
;gr1
輸出 12
之後,又切換至 gr2
;接著 gr2
輸出 56
後,又切換回 gr1
之前的切出點,繼續輸出 34
;這是 gr1
結束了,系統會自動切換回 gr1
的父微執行緒——也就是
main 的最後一句 switch()
返回,至此整個程式結束。注意,78
並沒有機會被輸出。
Gevent 的主迴圈叫做 Hub
,跑在一個單獨的
greenlet 裡。使用者的程式從 main greenlet 開始執行,直至第一個非同步切換。此時,Gevent 會把當前微執行緒——也就是 main ——與非同步事件做一個關聯,然後切換到 Hub
;Hub
於是開始運轉,當某些事件發生時,Gevent 就會切換到相應關聯的
greenlet 來執行,直至他們結束返回 Hub
,或者主動切換回 Hub
。比如
main 等待的事件發生了,Hub
就會切到 main 上執行——當然,如果這時 main 結束了,就不會像其他 greenlet 一樣再返回 Hub
了。
所以,greenlet 和 generator、Deferred
一樣,其實都是用來實現回撥封裝的一些工具,所以前面提到過的一些非同步併發的注意事項,Gevent 也都適用。
互操作性存在的問題
多種框架的存在,說好聽了是百花齊放各顯神通、競爭才有發展,說難聽了就是碎片化、選擇恐懼症和維護代價巨大。比如說,同樣是一個 Python 的 PostgreSQL 連線適配程式,有支援 Twisted 的 txpostgres,有支援 Tornado 的 momoko,還有 Gevent 需要的 psycogreen——有啥話咱不能一氣兒說完呢?如果上游的 psycopg 更新了,這麼多的介面卡,是不是得要跟著更新哪。
再一個問題就是遺留程式碼。如果一個專案一直在用 Twisted,有一天老闆拿著張光碟說給我把這個弄上去,開啟一看全都是 .pyc
檔案,木有原始碼——直接呼叫會有之前提到的阻塞主執行緒的問題,扔到執行緒池裡做又不甘心。如果能在 Twisted 裡用 Gevent 就好了(現在確實可以,不過會替換
Twisted 的一部分)。
未來
asyncio 這個專案其實叫做 tulip,主要開發也都在那裡,因為要進 Python 標準庫了,所以才幾經周折選了 asyncio 這麼一個名字。asyncio 是 Python 作者的一個新專案,要求至少是 Python 3.3(手動安裝),Python 3.4 裡它就已經是標準庫的一部分了。
之所以要求 Python 3.3,是因為 asyncio 的微執行緒依賴於 Python 3.3 的新語法:yield
from
。區別於 yield
,yield
from co
實現了類似於這樣的功能:
for x in co:
yield x
這裡說“類似”,是因為實際情況要比這複雜很多,但意思是一樣的:將內層迭代器的元素無縫地合併到外層的迭代器裡。有了這個,asyncio 就可以很容易地做微執行緒的嵌套了——也就是在一個微執行緒裡面等待另一個結束返回結果。
asyncio 作為又一個非同步併發框架,與其他現有框架差別並不大:主迴圈類似於 Twisted 的
reactor,
呵呵,這個標題有點大,其實只是想從零開始介紹一下非同步的基礎,以及 Python 開源非同步併發框架的發展和互操作性。
另外,這是我在 OSTC 2014 做的一個同題演講,幻燈片在這裡,歡迎拍磚。
開源
Python 是開源的,介紹的這幾個框架 Twisted、Tornado、Gevent 和 tu
本文主要介紹python非同步併發模組.。它非常簡單易用,主要用來實現多執行緒和多程序的非同步併發。
1. 模組安裝
2) python 2.7需要安裝模組,使用命令pip
install futures安裝即可
2. Executor物件
class .f 我們繼續學習Python非同步程式設計,這裡將介紹非同步Web框架sanic,為什麼不是tornado?從框架的易用性來說,Flask要遠遠比tornado簡單,可惜flask不支援非同步,而sanic就是類似Flask語法的非同步框架。
github:https://github.com/huge-suc
關於併發、並行、同步阻塞、非同步非阻塞、執行緒、程序、協程等這些概念,單純通過文字恐怕很難有比較深刻的理解,本文就通過程式碼一步步實現這些併發和非同步程式設計,並進行比較。直譯器方面本文選擇python3,畢竟python3才是python的未來,並且pytho
在python裡,按照官方解釋greenlet是輕量級的並行程式設計,而gevent呢,就是利用greenlet實現的基於協程的python的網路library,好了,關係理清了。。。
協程,gevent,gr
RPC包括:訊息的編碼、解碼、讀取和傳送;
轉自:http://blog.csdn.net/woshisap/article/details/74022825
本文是對上述文章的總結、精簡。2.1. RPC呼叫的效能模型分析2.1.1. 傳統RPC呼叫效能差的三宗罪
網路 目錄[python非同步程式設計之asyncio(百萬併發)]一、asyncio二、aiohttp
[python非同步程式設計之asyncio(百萬併發)]
前言:python由於GIL(全域性鎖)的存在,不能發揮多核的優勢,其效能一直飽受詬病。然而在IO密集型的網路程式設計裡,非同步處理比同步處理能提升成 驗證 觸發 pwd checkbox 參數 setup quest class 設置 在form表單以post的方式提交時,django默認會帶一個驗證的機制csrf驗證
<form action="/day02/login/" method="post">
楊文 python gateway 應用程序 服務器 第三方 所有的語言Web框架本質其實就是起一個socket服務端,監聽一個端口,然後運行起來Web框架包含兩部分,一部分是socket,另外一部分是業務的邏輯處理,根據請求的不同做不同的處理Python的Web框架分成了兩類,即包含 web框架 python 一、什麽是web框架?框架,就是一個為解決一個開放性問題而設計的具有一定約束性的支撐結構,使用框架可以幫你快速開發特定的系統,簡單地說,就是你用別人搭建好的舞臺來做表演。對於所有的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。 num pre 設置 span run type con sudo python flask配置redis
首先得下載flask的緩存插件Flask-Cache,使用pip下載。
sudo pip install flask_cache
為應用擴展flask_ca brush main 安裝 self name globals bject pytho log 1、安裝web.py模塊easy_install web.py
2、實現代碼
import web
urls = (‘/hello‘, ‘hello‘,
)
基於 比較 tex 性能 數據庫結構 客戶端 ebp best 分析 從GitHub中整理出的15個最受歡迎的Python開源框架。這些框架包括事件I/O,OLAP,Web開發,高性能網絡通信,測試,爬蟲等。Django: Python Web應用開發框架 Djang cnblogs alt frame fault .net lars 開源框架 pytho strong
http://www.csdn.net/article/2013-08-08/2816494-6-pillars-of-python-assessment-o span 技術 進行 target 最好 自己 blog height 描述 第一部分說明
第一部分大概有20來章,主要講的是一些開發常識、開發前中後期準備內容、開發環境與服務器部署環境安裝設置、python基礎框架結構與功能等內容,代碼會比較簡單。
數據結構 描述 分析器 設置 一個 由於 logs 記錄 開發框架 小白做好前端html設計後,馬上開始進入數據庫結構設計步驟。
在開始之前,小白回憶了一下老大在公司裏培訓時講過的數據庫設計解說:
對於初學者來說,很多拿到原型時不知道怎麽設計數據表結 turn 框架 strong pep8 加密與解密 python開發 lan 二次 沒有 中午吃飯時間到了,小白趕緊向老菜坐的位置走過去。
小白:老大,中午請你吃飯。
老菜:哈哈...又遇到問題了吧,這次得狠狠宰你一頓才行。
小白:行行行,只要您賞臉, getcwd 轉義 導航菜單 unicode 存儲路徑 -c 序號 管理 bsp 完成登錄以後,就會進入後臺管理系統的主界面,因為這個是小項目,所以導航菜單全部固化在HTML中,不能修改。一般後臺還會有一個歡迎頁或關鍵數據展示的主頁面,小項目也沒有多大的必要,所以登錄後 計算 添加按鈕 _for records 操作 qq群 api 回復 derby 產品分類管理的html頁面之前忘記做了,這次附件裏補上。
好了先上圖
從頁面效果圖來看,我們需要開發列表獲取接口、添加接口、單條記錄獲取接口、編輯接口和刪除接口
問題分析 odin message handlers 自己 file trac 配置 statement 引:
之前使用nose框架時,一直使用--logging-config的log文件來生成日誌,具體的log配置可見之前python nose測試框架全面介紹四。
但使用
相關推薦
Python非同步併發框架
python非同步併發模組concurrent.futures簡析
python 非同步Web框架sanic
python的併發和非同步程式設計例項
python Gevent – 高效能的Python併發框架
Java非同步NIO框架Netty實現高效能高併發
python非同步程式設計之asyncio(百萬併發)
python中django框架的csrf驗證
Python之Web框架介紹
13.python中web框架概念的引入。
Python的Flask框架使用Redis做數據緩存的配置方法
Python簡單Web框架web.py實例hello world
Python 常用Web框架的比較
Python六大開源框架對比:Web2py略勝一籌
我的第一個python web開發框架(2)——一個簡單的小外包
我的第一個python web開發框架(4)——數據庫結構設計與創建
我的第一個python web開發框架(5)——開發前準備工作(了解編碼前需要知道的一些常識)
我的第一個python web開發框架(15)——公司介紹編輯功能
我的第一個python web開發框架(16)——產品分類管理
python nose測試框架全面介紹七--日誌相關