新聞中心
在現(xiàn)代應(yīng)用程序中,從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)始終是一個(gè)重要的任務(wù)。 許多應(yīng)用程序具有數(shù)百個(gè)活躍的數(shù)據(jù)庫(kù)連接,并且隨著應(yīng)用程序規(guī)模的增長(zhǎng),這些連接數(shù)量會(huì)不斷增加。在這種情況下,從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)的效率成為了一個(gè)非常重要的問(wèn)題。 這就要求我們使用并發(fā)和異步方式來(lái)獲取數(shù)據(jù)庫(kù)數(shù)據(jù),以提高應(yīng)用性能和效率。在本文中,將討論如何使用并發(fā)異步方法來(lái)高效地獲取數(shù)據(jù)庫(kù)數(shù)據(jù)。

成都創(chuàng)新互聯(lián)是專(zhuān)業(yè)的翼城網(wǎng)站建設(shè)公司,翼城接單;提供成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行翼城網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
1.使用線程池
我們通常使用多線程的方式,使用線程池可以使程序獲得更好的性能。使用線程池時(shí),可以將數(shù)據(jù)庫(kù)連接池作為線程池的線程進(jìn)行調(diào)度。在這種方式下,線程池將會(huì)負(fù)責(zé)管理連接數(shù)量以及連接的狀態(tài)。同時(shí),線程池還可以根據(jù)當(dāng)前的負(fù)載情況來(lái)自動(dòng)調(diào)整線程數(shù)量,并且根據(jù)負(fù)載的大小來(lái)管理線程池。
2.使用異步/非阻塞I/O
使用異步/非阻塞I/O是降低網(wǎng)絡(luò)負(fù)荷的重要手段,這可以用在獲取數(shù)據(jù)庫(kù)數(shù)據(jù)的場(chǎng)景下。當(dāng)我們需要從數(shù)據(jù)庫(kù)中獲取大量數(shù)據(jù)時(shí),使用異步/非阻塞I/O可以使數(shù)據(jù)獲取和處理更加快速和高效。與傳統(tǒng)的阻塞式I/O相比,它可以并發(fā)地獲取和處理多個(gè)I/O操作。
3.使用數(shù)據(jù)庫(kù)連接池
使用數(shù)據(jù)庫(kù)連接池來(lái)高效地獲取數(shù)據(jù)非常重要。使用連接池可以有效地降低數(shù)據(jù)庫(kù)的I/O負(fù)荷。同時(shí),數(shù)據(jù)庫(kù)連接池可以幫助我們管理數(shù)據(jù)庫(kù)連接,減少連接的打開(kāi)和關(guān)閉所帶來(lái)的資源消耗,以及減少網(wǎng)絡(luò)流量和CPU的使用。
4.使用緩存
使用緩存可以減低數(shù)據(jù)庫(kù)I/O負(fù)荷,從而減少網(wǎng)絡(luò)負(fù)載和CPU使用。緩存可以將數(shù)據(jù)存儲(chǔ)在內(nèi)存中,讓你可以通過(guò)訪問(wèn)緩存數(shù)據(jù)而不是從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù),然后再返回到客戶(hù)端。這種方式可以大大減少?gòu)臄?shù)據(jù)庫(kù)中讀取數(shù)據(jù)的次數(shù),從而降低網(wǎng)絡(luò)負(fù)荷。
5.優(yōu)化SQL查詢(xún)
優(yōu)化SQL查詢(xún)也是極其重要的。通過(guò)優(yōu)化查詢(xún),我們可以大大提高數(shù)據(jù)庫(kù)查詢(xún)的效率,減少數(shù)據(jù)庫(kù)I/O負(fù)荷和CPU使用。優(yōu)化查詢(xún)的方法有很多,例如,改善表結(jié)構(gòu)、添加索引和使用分區(qū)等。
在使用并發(fā)異步方式獲取數(shù)據(jù)庫(kù)數(shù)據(jù)時(shí),你需要注意以下幾點(diǎn):使用線程池、使用異步/非阻塞I/O、使用數(shù)據(jù)庫(kù)連接池、使用緩存和優(yōu)化SQL查詢(xún)。合理運(yùn)用這些技巧可以有效地提高應(yīng)用程序的性能和效率。當(dāng)然,另外一個(gè)非常重要的問(wèn)題是, 如何設(shè)置開(kāi)發(fā)計(jì)劃,安排任務(wù),制定技術(shù)規(guī)范?那就需要更綜合的分析和研究。
相關(guān)問(wèn)題拓展閱讀:
- python2.7怎么實(shí)現(xiàn)異步
- 并發(fā)編程-同步、異步、阻塞、非阻塞
- 在編程里面,什么是異步,并發(fā),面向?qū)ο螅^(guò)程 ,什么意思啊?
python2.7怎么實(shí)現(xiàn)異步
您好,請(qǐng)問(wèn)您是想知道python2.7怎么實(shí)現(xiàn)異步嗎?
改進(jìn)之前
之前,我的查詢(xún)步驟很簡(jiǎn)單,就是:
前端提交查詢(xún)請(qǐng)求 –> 建立數(shù)據(jù)庫(kù)連接 –> 新建游標(biāo) –> 執(zhí)行命令 –> 接受結(jié)果 –> 關(guān)閉游標(biāo)、連接
這幾大步驟的順序執(zhí)行。
這里面當(dāng)然問(wèn)題很大:
建立數(shù)據(jù)庫(kù)連接實(shí)際上就是新建一個(gè)套接字。這是進(jìn)程間通信的幾種方法里,開(kāi)銷(xiāo)更大的了。
在“執(zhí)行命令”和“接受結(jié)果”兩個(gè)步驟中,線程在阻塞在數(shù)據(jù)庫(kù)內(nèi)部的運(yùn)行過(guò)程中,數(shù)據(jù)庫(kù)連接和游標(biāo)都處于閑置狀態(tài)。
這樣一來(lái),每一次查詢(xún)都要順序的新建數(shù)據(jù)庫(kù)連接,都要阻塞在數(shù)據(jù)庫(kù)返回結(jié)果的過(guò)程中。當(dāng)前端提交大量查詢(xún)請(qǐng)求時(shí),查詢(xún)效率肯定是很低的。
之一次改進(jìn)
之前的模塊里,問(wèn)題更大的就是之一步——建立數(shù)據(jù)庫(kù)連接套接字了。如果大碰能夠一次性建立連接,之后查詢(xún)能夠反復(fù)服用這個(gè)連接就好了。
所以,首先應(yīng)該把數(shù)據(jù)庫(kù)查詢(xún)模塊作為一個(gè)單獨(dú)的守護(hù)進(jìn)程去執(zhí)行,而前端app作為主進(jìn)程響應(yīng)用戶(hù)的點(diǎn)擊操作。那么兩條進(jìn)程怎么傳遞消息呢?翻了幾天Python文檔,終于構(gòu)思出來(lái):用隊(duì)列queue作為生產(chǎn)者(web前端)向消費(fèi)者(數(shù)據(jù)庫(kù)后端)傳遞任務(wù)的渠道。生產(chǎn)者,會(huì)與SQL命令一起,同時(shí)傳遞一個(gè)管道pipe的連接對(duì)象,作為任務(wù)完成后,回傳結(jié)果的渠道。確保,任務(wù)的接收方與發(fā)送方保持一致。
作為第二個(gè)問(wèn)題的解決方法,可以使用線程池來(lái)并發(fā)獲取任務(wù)隊(duì)列中的task,然后執(zhí)行命令并回傳結(jié)果。
第二次改進(jìn)
之一次改進(jìn)的效果還是很明顯的,不用任何測(cè)試手段。直接點(diǎn)擊頁(yè)面鏈接,可以很直觀地感覺(jué)到反者判應(yīng)速度有很明顯的加快。
但是對(duì)于第二個(gè)問(wèn)題,使用線程池還是有些欠妥當(dāng)。因?yàn)椋珻Python解釋器存在GIL問(wèn)題,所有線程實(shí)際上都在一個(gè)解釋器進(jìn)程里調(diào)度。線程稍微開(kāi)多一點(diǎn),解釋器進(jìn)程就會(huì)頻繁的切換線程,而線程切換的開(kāi)銷(xiāo)也不小。線程多一點(diǎn),甚至?xí)霈F(xiàn)“抖動(dòng)”問(wèn)題(也就是剛剛喚醒一個(gè)線程,就進(jìn)入掛起狀態(tài),剛剛換到棧幀或內(nèi)存的上下文,又被換回內(nèi)存或者磁盤(pán)),效率大大降低。也就是說(shuō),線程池的并發(fā)量很有限。
試過(guò)了多進(jìn)程、多線程,只能在單個(gè)線程里做文章了。
Python中的asyncio庫(kù)
Python里有大量的協(xié)程庫(kù)可以實(shí)現(xiàn)單線程內(nèi)的并發(fā)操作,比如Twisted、Gevent等等。Python官方在3.5版本里提供了asyncio庫(kù)同樣可以實(shí)現(xiàn)協(xié)程并發(fā)。asyncio庫(kù)大大降低了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ā)。
不過(guò)需要注意的是,run_until_complete()函數(shù)本身是一個(gè)阻塞函數(shù)。也就是說(shuō),當(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è)問(wèn)題首仿改,asyncio庫(kù)也有相應(yīng)的解決方案:gather函數(shù)。
loop = asyncio.get_event_loop()
tasks =
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í)際上,也存在上下文切換,只不過(guò)開(kāi)銷(xiāo)很輕微。而I/O多路復(fù)用則完全不存在這個(gè)問(wèn)題。
目前,Linux上比較火的I/O多路復(fù)用API要算epoll了。Tornado,就是通過(guò)調(diào)用C語(yǔ)言封裝的epoll庫(kù),成功解決了C10K問(wèn)題(當(dāng)然還有Pypy的功勞)。
在Linux里查文檔,可以看到epoll只有三類(lèi)函數(shù),調(diào)用起來(lái)比較方便易懂。
創(chuàng)建epoll對(duì)象,并返回其對(duì)應(yīng)的文件描述符(file descriptor)。
int epoll_create(int size);
int epoll_create1(int flags);
控制監(jiān)聽(tīng)事件。之一個(gè)參數(shù)epfd就對(duì)應(yīng)于前面命令創(chuàng)建的epoll對(duì)象的文件描述符;第二個(gè)參數(shù)表示該命令要執(zhí)行的動(dòng)作:監(jiān)聽(tīng)事件的新增、修改或者刪除;第三個(gè)參數(shù),是要監(jiān)聽(tīng)的文件對(duì)應(yīng)的描述符;第四個(gè),代表要監(jiān)聽(tīng)的事件。
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庫(kù)里:
select.epoll()對(duì)應(yīng)于之一類(lèi)創(chuàng)建函數(shù);
epoll.register(),epoll.unregister(),epoll.modify()均是對(duì)控制函數(shù)epoll_ctl的封裝;
epoll.poll()則是對(duì)等候函數(shù)epoll_wait的封裝。
Python里epoll相關(guān)API的更大問(wèn)題應(yīng)該是在epoll.poll()。相比于其所封裝的epoll_wait,用戶(hù)無(wú)法手動(dòng)指定要等候的事件,也就是后者的第二個(gè)參數(shù)struct epoll_event *events。沒(méi)法實(shí)現(xiàn)精確控制。因此只能使用替代方案:select.select()函數(shù)。
根據(jù)Python官方文檔,select.select(rlist, wlist, xlist)是對(duì)Unix系統(tǒng)中select函數(shù)的直接調(diào)用,與C語(yǔ)言API的傳參很接近。前三個(gè)參數(shù)都是列表,其中的元素都是要注冊(cè)到內(nèi)核的文件描述符。如果想用自定義類(lèi),就要確保實(shí)現(xiàn)了fileno()方法。
其分別對(duì)應(yīng)于:
rlist: 等候直到可讀
wlist: 等候直到可寫(xiě)
xlist: 等候直到異常。這個(gè)異常的定義,要查看系統(tǒng)文檔。
select.select(),類(lèi)似于epoll.poll(),先注冊(cè)文件和事件,然后保持等候內(nèi)核通知,是阻塞函數(shù)。
實(shí)際應(yīng)用
Psycopg2庫(kù)支持對(duì)異步和協(xié)程,但和一般情況下的用法略有區(qū)別。普通數(shù)據(jù)庫(kù)連接支持不同線程中的不同游標(biāo)并發(fā)查詢(xún);而異步連接則不支持不同游標(biāo)的同時(shí)查詢(xún)。所以異步連接的不同游標(biāo)之間必須使用I/O復(fù)用方法來(lái)協(xié)調(diào)調(diào)度。
所以,我的大致實(shí)現(xiàn)思路是這樣的:首先并發(fā)執(zhí)行大量協(xié)程,從任務(wù)隊(duì)列中提取任務(wù),再向連接池請(qǐng)求連接,創(chuàng)建游標(biāo),然后執(zhí)行命令,并返回結(jié)果。在獲取游標(biāo)和接受查詢(xún)結(jié)果之前,均要阻塞等候內(nèi)核通知連接可用。
其中,連接池返回連接時(shí),會(huì)根據(jù)引用連接的協(xié)程數(shù)量,返回負(fù)載最輕的連接。這也是自己定義AsyncConnectionPool類(lèi)的目的。
我的代碼位于:bottle-blog/dbservice.py
存在問(wèn)題
當(dāng)然了,這個(gè)流程目前還一些問(wèn)題。
首先就是每次輪詢(xún)拿到任務(wù)之后,都會(huì)走這么一個(gè)流程。
獲取連接 –> 新建游標(biāo) –> 執(zhí)行任務(wù) –> 關(guān)閉游標(biāo) –> 取消連接引用
本來(lái),更好的情況應(yīng)該是:在輪詢(xún)之前,就建好游標(biāo);在輪詢(xún)時(shí),直接等候內(nèi)核通知,執(zhí)行相應(yīng)任務(wù)。這樣可以減少輪詢(xún)時(shí)的任務(wù)量。但是如果協(xié)程提前對(duì)應(yīng)好連接,那就不能保證在獲取任務(wù)時(shí),保持各連接負(fù)載均衡了。
所以這一塊,還有工作要做。
還有就是epoll沒(méi)能用上,有些遺憾。
以后打算寫(xiě)點(diǎn)C語(yǔ)言的內(nèi)容,或者用Python/C API,或者用Ctypes包裝共享庫(kù),來(lái)實(shí)現(xiàn)epoll的調(diào)用。
并發(fā)編程-同步、異步、阻塞、非阻塞
同步執(zhí)行:一個(gè)進(jìn)程在執(zhí)行某個(gè)任務(wù)時(shí),另外一個(gè)進(jìn)程必須等待其執(zhí)行完畢,才能繼續(xù)執(zhí)行
異步執(zhí)行:一個(gè)進(jìn)程在執(zhí)行某個(gè)任務(wù)時(shí),另外一個(gè)進(jìn)程無(wú)需等待其執(zhí)行完畢,就可以繼續(xù)執(zhí)行,當(dāng)有消息返回時(shí),系統(tǒng)會(huì)通知后者進(jìn)行處理,這樣可以提高執(zhí)行效率
所謂同步,就是在發(fā)出一個(gè)功能調(diào)用時(shí),在沒(méi)有得到結(jié)果之前,該調(diào)用就不會(huì)返回。按照這個(gè)定義,其實(shí)絕大多數(shù)函數(shù)都是同步調(diào)用。但是一般而言,我們?cè)谡f(shuō)同步、異步的時(shí)候,特指那些需要其他部件協(xié)作或者需要一定時(shí)此罩間完成的任務(wù)。
異步的概念和同步相對(duì)。當(dāng)一個(gè)異步功能調(diào)用發(fā)出后,調(diào)用者森納鬧不能立刻得到結(jié)果。當(dāng)該異步功能完成后,通過(guò)狀態(tài)、通知或回調(diào)來(lái)通知調(diào)用者。如果異步功能用狀態(tài)來(lái)通知,那么調(diào)用者就需要每隔一定時(shí)間檢查一次,效率就很低(有些初學(xué)多線程編程的人,總喜歡用一個(gè)循環(huán)去檢查某個(gè)變量的值,這其實(shí)是一 種很?chē)?yán)重的錯(cuò)誤)。如果是使用通知的方式,效率則很高,因?yàn)楫惒焦δ軒缀醪恍枰鲱~外的操作。至于回調(diào)函數(shù),其實(shí)和通知沒(méi)太多區(qū)別。
阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起(如遇到io操作)。函數(shù)只有在得到結(jié)果之后才會(huì)將阻塞的線程激活。有人也許會(huì)把阻塞調(diào)用和同步調(diào)用等同起來(lái),實(shí)際上他是不同的。對(duì)于同步調(diào)用來(lái)說(shuō),很多時(shí)候當(dāng)前線程還是激活的,只是從邏輯上當(dāng)前函數(shù)沒(méi)有返回而已。
非阻塞和阻塞的概念相對(duì)應(yīng),指在不能立刻得到結(jié)果之前也會(huì)立刻返回,同時(shí)該函數(shù)不會(huì)阻塞當(dāng)前線程。
1. 同步與異步針對(duì)的是函數(shù)/任務(wù)的調(diào)用方式:同步就是當(dāng)一個(gè)進(jìn)程發(fā)起一個(gè)函數(shù)(任務(wù))調(diào)用的時(shí)候,一直等到函數(shù)(任務(wù))完成,而進(jìn)程繼續(xù)處于激活狀態(tài)。而異步情況下是當(dāng)一個(gè)進(jìn)程發(fā)起一個(gè)函數(shù)(任務(wù))調(diào)用的時(shí)候,不會(huì)等函數(shù)返回,而是茄迅繼續(xù)往下執(zhí)行當(dāng),函數(shù)返回的時(shí)候通過(guò)狀態(tài)、通知、事件等方式通知進(jìn)程任務(wù)完成。
2. 阻塞與非阻塞針對(duì)的是進(jìn)程或線程:阻塞是當(dāng)請(qǐng)求不能滿(mǎn)足的時(shí)候就將進(jìn)程掛起,而非阻塞則不會(huì)阻塞當(dāng)前進(jìn)程,同步和異步的時(shí)候當(dāng)前的進(jìn)程/線程一直是激活狀態(tài)
在編程里面,什么是異步,并發(fā),面向?qū)ο螅^(guò)程 ,什么意思???
C語(yǔ)言是面向過(guò)程的編程,它的最重要特巖埋點(diǎn)是函數(shù),通過(guò)主函數(shù)來(lái)調(diào)用一個(gè)個(gè)子函數(shù)。程序運(yùn)行的順序都是程序員決定好了的。它是我學(xué)的之一種程序語(yǔ)言。 C++是面向?qū)ο蟮拇置魑浘幊蹋?lèi)是它的主要特點(diǎn),程序執(zhí)行過(guò)槐李程中,先由主函數(shù)進(jìn)入,定義一些類(lèi),根據(jù)需…
關(guān)于并發(fā)異步get數(shù)據(jù)庫(kù)的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開(kāi)通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過(guò)10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開(kāi)發(fā)經(jīng)驗(yàn)。專(zhuān)業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊(cè)、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
分享名稱(chēng):如何高效利用并發(fā)異步方式獲取數(shù)據(jù)庫(kù)數(shù)據(jù)(并發(fā)異步get數(shù)據(jù)庫(kù))
文章來(lái)源:http://fisionsoft.com.cn/article/dpddjcd.html


咨詢(xún)
建站咨詢(xún)
