內(nèi)置函數(shù),在python幫助文檔中:Build-in Functions
創(chuàng)新互聯(lián)公司是一家專業(yè)提供蘄春企業(yè)網(wǎng)站建設(shè),專注與成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、H5建站、小程序制作等業(yè)務(wù)。10年已為蘄春眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進(jìn)行中。
在Python提示符下,輸入下面語句,就會(huì)顯示Python提供的內(nèi)置函數(shù)列表
dir('__builtins__')
abs(_) 內(nèi)置函數(shù),絕對(duì)值或復(fù)數(shù)的模。
chr() 以單字節(jié)整數(shù)為參數(shù),返回一個(gè)單字符的字符串,其內(nèi)容是與之對(duì)于的ASCII字符。如chr(69)返回'E'。
cmp() 比較字符串,cmp('Xiao','Jian')返回1
coerce() (可以看成一個(gè)數(shù)值類型轉(zhuǎn)換函數(shù))有兩個(gè)參數(shù),都是數(shù)字,返回這兩個(gè)數(shù)字的一個(gè)列表,將這兩個(gè)數(shù)字的數(shù)據(jù)類型統(tǒng)一。如coerce(1,2j),返回(1+0j,2j)
complex() 內(nèi)置函數(shù),把……轉(zhuǎn)換成復(fù)數(shù),如complex('2')返回(2+0j),complex('2+3j')返回(2+3j)。
divmod() 內(nèi)置函數(shù),有兩個(gè)參數(shù),返回(商,余數(shù))。如divmod(10,2.5),返回(4.0,0.0)。
filter(function,list) 把函數(shù)應(yīng)用于list中的每一項(xiàng),并返回 從函數(shù)中返回真值的項(xiàng)。注:function可以為None,此時(shí)刪除list中的0或空項(xiàng)。
float() 內(nèi)置函數(shù),把……轉(zhuǎn)換成浮點(diǎn)數(shù)。
floor() 在math模塊內(nèi),需要import math。向下取整,即向x軸負(fù)方向取整。如math.floor(1.9)返回1,math.floor(-2.5)返回-3。
hash() 散列功能,詞典鍵的最精確功能需求是它一定是可散列的。對(duì)象的散列值是半唯一的、內(nèi)部生成的數(shù)字,它可用于快速比較。
int() 內(nèi)置函數(shù),把字符串或者小數(shù)轉(zhuǎn)換為一個(gè)整數(shù)。直接去掉小數(shù)部分。如int(5.3)返回5,int('5')返回5。
len(x) 序列x的長(zhǎng)度
long() 內(nèi)置函數(shù),把數(shù)字 或 代表整數(shù)的字符串 轉(zhuǎn)換成長(zhǎng)整型
map(function,list[,list,...])
max() 找出字符串中最大的字符。如:min('find the minimum character'),返回' ',即空格。
min() 找出字符串中最小的字符。如:max('find the maximum character'),返回'x'。
oct() 將十進(jìn)制數(shù)轉(zhuǎn)換成八進(jìn)制,再變成字符。
ord() 參數(shù)是單個(gè)的ASCII字符,返回該ASCII字符對(duì)應(yīng)的整數(shù)值,如ord('a')返回97。
pow() 內(nèi)置函數(shù),乘方。如果有第三個(gè)參數(shù),則表示乘方的結(jié)果對(duì)第三參數(shù)取余,如pow(2,3)返回8,pow(2,3,4)返回0。
print 輸出到窗口
range() 生成一個(gè)向量,例如range(m,n,d),從m到n,步長(zhǎng)為d;range(m)則生成0:m-1,步長(zhǎng)為1的向量。
raw_input() 輸入函數(shù),參數(shù)為字符串,作為輸入時(shí)的提示語句。返回值為字符串。
reduce(func)
round() 內(nèi)置函數(shù),對(duì)數(shù)字進(jìn)行四舍五入,第二個(gè)參數(shù)表示精確到小數(shù)點(diǎn)后指定的位數(shù),默認(rèn)值為0。如round(2.4)返回2,round(1.398,2)返回1.40。
type() 返回某數(shù)據(jù)的類型
語法:isinstance(object,typeinfo)
作用:來判斷一個(gè)對(duì)象(參數(shù)object)是否是一個(gè)已知的類型(參數(shù)typeinfo)的實(shí)例。
其第一個(gè)參數(shù)(object)為對(duì)象實(shí)例,第二個(gè)參數(shù)(typeinfo)為類型名(int...)或類型名的一個(gè)列表((int,list,float)是一個(gè)列表)。其返回值為布爾型(True or flase)。
若對(duì)象的類型與參數(shù)二的類型相同則返回True。若參數(shù)二為一個(gè)元組,則若對(duì)象類型與元組中類型名之一相同即返回True。
通常也可以用type(),不過用 type的話,并不是很準(zhǔn)確,比如在舊式類繼承方面,子類的實(shí)例應(yīng)該也算是父類的實(shí)例的,但是用type的話就不是了
改進(jìn)之前
之前,我的查詢步驟很簡(jiǎn)單,就是:
前端提交查詢請(qǐng)求 -- 建立數(shù)據(jù)庫連接 -- 新建游標(biāo) -- 執(zhí)行命令 -- 接受結(jié)果 -- 關(guān)閉游標(biāo)、連接
這幾大步驟的順序執(zhí)行。
這里面當(dāng)然問題很大:
建立數(shù)據(jù)庫連接實(shí)際上就是新建一個(gè)套接字。這是進(jìn)程間通信的幾種方法里,開銷最大的了。
在“執(zhí)行命令”和“接受結(jié)果”兩個(gè)步驟中,線程在阻塞在數(shù)據(jù)庫內(nèi)部的運(yùn)行過程中,數(shù)據(jù)庫連接和游標(biāo)都處于閑置狀態(tài)。
這樣一來,每一次查詢都要順序的新建數(shù)據(jù)庫連接,都要阻塞在數(shù)據(jù)庫返回結(jié)果的過程中。當(dāng)前端提交大量查詢請(qǐng)求時(shí),查詢效率肯定是很低的。
第一次改進(jìn)
之前的模塊里,問題最大的就是第一步——建立數(shù)據(jù)庫連接套接字了。如果能夠一次性建立連接,之后查詢能夠反復(fù)服用這個(gè)連接就好了。
所以,首先應(yīng)該把數(shù)據(jù)庫查詢模塊作為一個(gè)單獨(dú)的守護(hù)進(jìn)程去執(zhí)行,而前端app作為主進(jìn)程響應(yīng)用戶的點(diǎn)擊操作。那么兩條進(jìn)程怎么傳遞消息呢?翻了幾天Python文檔,終于構(gòu)思出來:用隊(duì)列queue作為生產(chǎn)者(web前端)向消費(fèi)者(數(shù)據(jù)庫后端)傳遞任務(wù)的渠道。生產(chǎn)者,會(huì)與SQL命令一起,同時(shí)傳遞一個(gè)管道pipe的連接對(duì)象,作為任務(wù)完成后,回傳結(jié)果的渠道。確保,任務(wù)的接收方與發(fā)送方保持一致。
作為第二個(gè)問題的解決方法,可以使用線程池來并發(fā)獲取任務(wù)隊(duì)列中的task,然后執(zhí)行命令并回傳結(jié)果。
第二次改進(jìn)
第一次改進(jìn)的效果還是很明顯的,不用任何測(cè)試手段。直接點(diǎn)擊頁面鏈接,可以很直觀地感覺到反應(yīng)速度有很明顯的加快。
但是對(duì)于第二個(gè)問題,使用線程池還是有些欠妥當(dāng)。因?yàn)椋珻Python解釋器存在GIL問題,所有線程實(shí)際上都在一個(gè)解釋器進(jìn)程里調(diào)度。線程稍微開多一點(diǎn),解釋器進(jìn)程就會(huì)頻繁的切換線程,而線程切換的開銷也不小。線程多一點(diǎn),甚至?xí)霈F(xiàn)“抖動(dòng)”問題(也就是剛剛喚醒一個(gè)線程,就進(jìn)入掛起狀態(tài),剛剛換到棧幀或內(nèi)存的上下文,又被換回內(nèi)存或者磁盤),效率大大降低。也就是說,線程池的并發(fā)量很有限。
試過了多進(jìn)程、多線程,只能在單個(gè)線程里做文章了。
Python中的asyncio庫
Python里有大量的協(xié)程庫可以實(shí)現(xiàn)單線程內(nèi)的并發(fā)操作,比如Twisted、Gevent等等。Python官方在3.5版本里提供了asyncio庫同樣可以實(shí)現(xiàn)協(xié)程并發(fā)。asyncio庫大大降低了Python中協(xié)程的實(shí)現(xiàn)難度,就像定義普通函數(shù)那樣就可以了,只是要在def前面多加一個(gè)async關(guān)鍵詞。async def函數(shù)中,需要阻塞在其他async def函數(shù)的位置前面可以加上await關(guān)鍵詞。
import asyncio
async def wait():
await asyncio.sleep(2)
async def execute(task):
process_task(task)
await wait()
continue_job()
async def函數(shù)的執(zhí)行稍微麻煩點(diǎn)。需要首先獲取一個(gè)loop對(duì)象,然后由這個(gè)對(duì)象代為執(zhí)行async def函數(shù)。
loop = asyncio.get_event_loop()
loop.run_until_complete(execute(task))
loop.close()
loop在執(zhí)行execute(task)函數(shù)時(shí),如果遇到await關(guān)鍵字,就會(huì)暫時(shí)掛起當(dāng)前協(xié)程,轉(zhuǎn)而去執(zhí)行其他阻塞在await關(guān)鍵詞的協(xié)程,從而實(shí)現(xiàn)協(xié)程并發(fā)。
不過需要注意的是,run_until_complete()函數(shù)本身是一個(gè)阻塞函數(shù)。也就是說,當(dāng)前線程會(huì)等候一個(gè)run_until_complete()函數(shù)執(zhí)行完畢之后,才會(huì)繼續(xù)執(zhí)行下一部函數(shù)。所以下面這段代碼并不能并發(fā)執(zhí)行。
for task in task_list:
loop.run_until_complete(task)
對(duì)與這個(gè)問題,asyncio庫也有相應(yīng)的解決方案:gather函數(shù)。
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(execute(task))
for task in task_list]
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()
當(dāng)然了,async def函數(shù)的執(zhí)行并不只有這兩種解決方案,還有call_soon與run_forever的配合執(zhí)行等等,更多內(nèi)容還請(qǐng)參考官方文檔。
Python下的I/O多路復(fù)用
協(xié)程,實(shí)際上,也存在上下文切換,只不過開銷很輕微。而I/O多路復(fù)用則完全不存在這個(gè)問題。
目前,Linux上比較火的I/O多路復(fù)用API要算epoll了。Tornado,就是通過調(diào)用C語言封裝的epoll庫,成功解決了C10K問題(當(dāng)然還有Pypy的功勞)。
在Linux里查文檔,可以看到epoll只有三類函數(shù),調(diào)用起來比較方便易懂。
創(chuàng)建epoll對(duì)象,并返回其對(duì)應(yīng)的文件描述符(file descriptor)。
int epoll_create(int size);
int epoll_create1(int flags);
控制監(jiān)聽事件。第一個(gè)參數(shù)epfd就對(duì)應(yīng)于前面命令創(chuàng)建的epoll對(duì)象的文件描述符;第二個(gè)參數(shù)表示該命令要執(zhí)行的動(dòng)作:監(jiān)聽事件的新增、修改或者刪除;第三個(gè)參數(shù),是要監(jiān)聽的文件對(duì)應(yīng)的描述符;第四個(gè),代表要監(jiān)聽的事件。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
等候。這是一個(gè)阻塞函數(shù),調(diào)用者會(huì)等候內(nèi)核通知所注冊(cè)的事件被觸發(fā)。
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,
int maxevents, int timeout,
const sigset_t *sigmask);
在Python的select庫里:
select.epoll()對(duì)應(yīng)于第一類創(chuàng)建函數(shù);
epoll.register(),epoll.unregister(),epoll.modify()均是對(duì)控制函數(shù)epoll_ctl的封裝;
epoll.poll()則是對(duì)等候函數(shù)epoll_wait的封裝。
Python里epoll相關(guān)API的最大問題應(yīng)該是在epoll.poll()。相比于其所封裝的epoll_wait,用戶無法手動(dòng)指定要等候的事件,也就是后者的第二個(gè)參數(shù)struct epoll_event *events。沒法實(shí)現(xiàn)精確控制。因此只能使用替代方案:select.select()函數(shù)。
根據(jù)Python官方文檔,select.select(rlist, wlist, xlist[, timeout])是對(duì)Unix系統(tǒng)中select函數(shù)的直接調(diào)用,與C語言API的傳參很接近。前三個(gè)參數(shù)都是列表,其中的元素都是要注冊(cè)到內(nèi)核的文件描述符。如果想用自定義類,就要確保實(shí)現(xiàn)了fileno()方法。
其分別對(duì)應(yīng)于:
rlist: 等候直到可讀
wlist: 等候直到可寫
xlist: 等候直到異常。這個(gè)異常的定義,要查看系統(tǒng)文檔。
select.select(),類似于epoll.poll(),先注冊(cè)文件和事件,然后保持等候內(nèi)核通知,是阻塞函數(shù)。
實(shí)際應(yīng)用
Psycopg2庫支持對(duì)異步和協(xié)程,但和一般情況下的用法略有區(qū)別。普通數(shù)據(jù)庫連接支持不同線程中的不同游標(biāo)并發(fā)查詢;而異步連接則不支持不同游標(biāo)的同時(shí)查詢。所以異步連接的不同游標(biāo)之間必須使用I/O復(fù)用方法來協(xié)調(diào)調(diào)度。
所以,我的大致實(shí)現(xiàn)思路是這樣的:首先并發(fā)執(zhí)行大量協(xié)程,從任務(wù)隊(duì)列中提取任務(wù),再向連接池請(qǐng)求連接,創(chuàng)建游標(biāo),然后執(zhí)行命令,并返回結(jié)果。在獲取游標(biāo)和接受查詢結(jié)果之前,均要阻塞等候內(nèi)核通知連接可用。
其中,連接池返回連接時(shí),會(huì)根據(jù)引用連接的協(xié)程數(shù)量,返回負(fù)載最輕的連接。這也是自己定義AsyncConnectionPool類的目的。
我的代碼位于:bottle-blog/dbservice.py
存在問題
當(dāng)然了,這個(gè)流程目前還一些問題。
首先就是每次輪詢拿到任務(wù)之后,都會(huì)走這么一個(gè)流程。
獲取連接 -- 新建游標(biāo) -- 執(zhí)行任務(wù) -- 關(guān)閉游標(biāo) -- 取消連接引用
本來,最好的情況應(yīng)該是:在輪詢之前,就建好游標(biāo);在輪詢時(shí),直接等候內(nèi)核通知,執(zhí)行相應(yīng)任務(wù)。這樣可以減少輪詢時(shí)的任務(wù)量。但是如果協(xié)程提前對(duì)應(yīng)好連接,那就不能保證在獲取任務(wù)時(shí),保持各連接負(fù)載均衡了。
所以這一塊,還有工作要做。
還有就是epoll沒能用上,有些遺憾。
以后打算寫點(diǎn)C語言的內(nèi)容,或者用Python/C API,或者用Ctypes包裝共享庫,來實(shí)現(xiàn)epoll的調(diào)用。
最后,請(qǐng)?jiān)试S我吐槽一下Python的epoll相關(guān)文檔:簡(jiǎn)直太弱了?。?!必須看源碼才能弄清楚功能。
新聞標(biāo)題:python2.7庫函數(shù) Python的庫函數(shù)
URL網(wǎng)址:http://m.rwnh.cn/article12/doopgdc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供、做網(wǎng)站、營(yíng)銷型網(wǎng)站建設(shè)、外貿(mào)建站、網(wǎng)站建設(shè)、商城網(wǎng)站
聲明:本網(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)