1. 程式人生 > >服務端的併發處理-多執行緒多程序

服務端的併發處理-多執行緒多程序

服務端的併發處理-多執行緒多程序

在服務端進行掛起監聽的時候,可能會遇到同時大量的使用者進行連線和資料請求,那麼單程序的可以使用多路複用的方式進行解決這個問題,這個技術後面再講,現在最簡單的解決方案就是使用多執行緒和多程序

多執行緒與多程序的選擇這取決於到底是IO密集型還是CPU密集型,IO密集型需要使用多執行緒,cpu密集型進行多程序

這裡顯然就是io密集型的,但是為了練習,現在使用多執行緒和多程序都實驗一把

from socket import *
from multiprocessing import Process


def main():
    # 建立物件
server = socket(AF_INET, SOCK_STREAM) # 配置斷開釋放埠 server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # 掛起伺服器 server.bind(('', 8888)) # 設定成監聽模式 server.listen() while True: # 建立新的連線物件 new_server, client_info = server.accept() # 建立新的程序 print(f'使用者{client_info}已經連線'
) p = Process(target=get_data, args=(new_server,client_info)) # 啟動程序 p.start() # 因為記憶體對應的new_server存在兩個指向,所以外面的必須關閉,否則無法釋放掉物件 new_server.close() def get_data(new_server,client_info): # 拿出資料 data = new_server.recv(1024) while data: # 列印資料 print
(f'來自{client_info}的資料{data}') # 如果一次沒有取完,繼續取 data = new_server.recv(1024) # 客戶端斷開連線後進行關閉處理 new_server.close() if __name__ == '__main__': main()

多程序與多執行緒的區別在於是否進行物件關閉

from socket import *
from threading import Thread


def main():
    # 建立物件
    server = socket(AF_INET, SOCK_STREAM)
    # 配置斷開釋放埠
    server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    # 掛起伺服器
    server.bind(('', 8888))
    # 設定成監聽模式
    server.listen()
    while True:
        # 建立新的連線物件
        new_server, client_info = server.accept()
        # 建立新的程序
        print(f'使用者{client_info}已經連線')
        t = Thread(target=get_data, args=(new_server,client_info))
        # 啟動執行緒
        t.start()
        # 因為多執行緒並不會複製程序的記憶體,所以new_server的指向不會出現兩個

def get_data(new_server,client_info):
    # 拿出資料
    data = new_server.recv(1024)
    while data:
        # 列印資料
        print(f'來自{client_info}的資料{data}')
        # 如果一次沒有取完,繼續取
        data = new_server.recv(1024)
    # 客戶端斷開連線後進行關閉處理
    new_server.close()


if __name__ == '__main__':
    main()

多程序的記憶體複製實質

籠統的認為多程序在開新程序的時候,子程序會複製父程序的記憶體空間,從而具備整整個父程序所具有的變數

這只是非常籠統的認為,實際上計算機記憶體的儲存方式分為兩種一種就是棧,一種是堆

在計算中,如果記憶體地址中的資料沒有變數指向它,則認為整個資料已經不需要了,系統就會對這個資料進行清空以釋放記憶體

實際在我們父程序中建立的物件new_server已經被存在記憶體裡面,父程序儲存的是一個指向這個資料的對映關係,那麼父程序在產生子程序的時候,子程序會複製父程序的這些對映關係,此時new_server物件對映的ip就有兩個變數指向這個記憶體空間,從而使得記憶體中的這個資料ip就會受到兩個指向

上面的進行多程序中,程序函式確實執行完成之後清空的子程序對這個資料ip的指向,子程序的對映關係唄刪除,然而這個資料ip還存在一個父程序的變數進行對映,系統發現記憶體中這個資料ip居然還有一個指向,因此不會進行刪除釋放記憶體

那麼回頭看程式碼,在父程序分裂出子程序後直接繼續執行,父程序馬上就對自己的對映關係進行刪除,此時整個記憶體裡面的資料ip不會消失,因為子程序中還有對這個資料ip的指向

如果子程序也刪除了自己的指向,系統就會知道這個資料ip已經沒有任何指向了,那麼系統就會清空這個資料ip,從而徹底結束這個new_server.

棧是一種先進後出的資料儲存模式,我們大部分變數名就存在這裡面,其優勢在於非常快,然而變數名並不是變數值,棧中儲存的都是一些對映方式

堆則不同,堆用來存大量的複雜資料,其容量大,但是速度慢

比如如果存在

a = 1

b = 1

那麼1這個資料就有兩個變數進行指向,所以資料1的對映數為2,當我們執行a += 1,此時變數名a指向的是2,而2是一個新的資料,在記憶體中會分配一個新的地址,此時資料1的對映數就減1稱為了1.系統之所以沒有清空資料1佔用的記憶體,因為b這個變數對映在資料1上面還有對映

敲黑板

如果此時對b進行 b += 1的操作,則此時就會執行,先將資料2上面增加一個對映關係,這個對映是b變數指向的,此時資料2存在的對映數為2,那麼原來的資料1就會減少一個對映關係,此時的資料1上的對映數為0,系統此時發現數據1上已經沒有映射了,那麼就會將資料0佔用的記憶體釋放掉,那麼ab兩個變數再次指向的是同一片記憶體空間