多任務簡單地說,就是操做系統能夠同時運行多個任務。分爲並行和併發兩種。python
指的是任務數小於等於CPU核數,即任務真的是一塊兒執行的算法
指的是任務數多於CPU核數,經過操做系統的各類任務調度算法,實現用多個任務一塊兒執行(實際上總有一些任務不在執行,由於切換任務的速度至關快,看上去一塊兒執行而已)瀏覽器
網絡就是輔助雙方或多方,鏈接在一塊兒的輔助工具服務器
網絡可以實現數據的相互傳送,可以通訊,互相傳遞信息等。網絡
ip地址就是在網絡中標記一臺計算機的地址,好比192.168.1.1;在本地局域網上是惟一的。多線程
是屬於私網IP,不在公網中使用的,它們的範圍是:併發
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
複製代碼
IP地址127.0.0.1~127.255.255.255用於迴路測試,app
如:127.0.0.1能夠表明本機IP地址,用http://127.0.0.1就能夠測試本機中配置的Web服務器。socket
端口號就是電腦上某個程序對應的地址,用來標記某個程序,端口號只有整數,範圍是從0到65535async
socket是一種進程之間的通訊方式,簡稱套接字。它能實現不一樣主機間的進程間通訊,咱們網絡上各類各樣的服務大多都是基於 Socket 來完成通訊的
例如咱們天天瀏覽網頁、QQ 聊天、收發 email 等等。
import socket
socket.socket(AddressFamily, Type)
複製代碼
說明:
函數 socket.socket 建立一個 socket,該函數帶有兩個參數:
Address Family:能夠選擇 AF_INET(用於 Internet 進程間通訊) 或者 AF_UNIX(用於同一臺機器進程間通訊),實際工做中經常使用AF_INET Type:套接字類型,能夠是 SOCK_STREAM(流式套接字,主要用於 TCP 協議)或者 SOCK_DGRAM(數據報套接字,主要用於 UDP 協議)
python的thread模塊是比較底層的模塊,python的threading模塊是對thread作了一些包裝的,能夠更加方便的被使用
#coding=utf-8
import threading
import time
def saySorry():
print("我能吃飯了嗎?")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=saySorry)
t.start() #啓動線程,即讓線程開始執行
複製代碼
python的threading.Thread類有一個run方法,用於定義線程的功能函數,能夠在本身的線程類中覆蓋該方法。而建立本身的線程實例後,經過Thread類的start方法,能夠啓動該線程,交給python虛擬機進行調度,當該線程得到執行的機會時,就會調用run方法執行線程。
多線程程序的執行順序是不肯定的。當執行到sleep語句時,線程將被阻塞,到sleep結束後,線程進入就緒狀態,等待調度。而線程調度將自行選擇一個線程執行。
當多個線程幾乎同時修改某個共享數據的時候,須要進行同步控制。
某個線程要更改共享數據時,先將其鎖定,此時資源的狀態爲「鎖定」,其餘線程不能更改;直到該線程釋放資源,將資源的狀態變成「非鎖定」,其餘的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操做,從而保證了多線程狀況下數據的正確性。
threading模塊中定義了Lock類,能夠方便的處理鎖定:
# 建立鎖
mutex = threading.Lock()
# 鎖定
mutex.acquire()
# 釋放
mutex.release()
複製代碼
在線程鍵共享多個資源的時候,若是兩個線程分別佔有一部分資源而且同時等待對方的資源,就會形成死鎖。
能夠添加超時時間等,解決死鎖
import socket
import threading
def send_msg(udp_socket):
"""獲取鍵盤數據,並將其發送給對方"""
while True:
# 1. 從鍵盤輸入數據
msg = input("\n請輸入要發送的數據:")
# 2. 輸入對方的ip地址
dest_ip = input("\n請輸入對方的ip地址:")
# 3. 輸入對方的port
dest_port = int(input("\n請輸入對方的port:"))
# 4. 發送數據
udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))
def recv_msg(udp_socket):
"""接收數據並顯示"""
while True:
# 1. 接收數據
recv_msg = udp_socket.recvfrom(1024)
# 2. 解碼
recv_ip = recv_msg[1]
recv_msg = recv_msg[0].decode("utf-8")
# 3. 顯示接收到的數據
print(">>>%s:%s" % (str(recv_ip), recv_msg))
def main():
# 1. 建立套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2. 綁定本地信息
udp_socket.bind(("", 7890))
# 3. 建立一個子線程用來接收數據
t = threading.Thread(target=recv_msg, args=(udp_socket,))
t.start()
# 4. 讓主線程用來檢測鍵盤數據而且發送
send_msg(udp_socket)
if __name__ == "__main__":
main()
複製代碼
multiprocessing模塊就是跨平臺版本的多進程模塊,提供了一個Process類來表明一個進程對象,這個對象能夠理解爲是一個獨立的進程,能夠執行另外的事情。
建立子進程時,只須要傳入一個執行函數和函數的參數,建立一個Process實例,用start()方法啓動
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
import time
def run_proc():
"""子進程要執行的代碼"""
print('子進程運行中,pid=%d...' % os.getpid()) # os.getpid獲取當前進程的進程號
print('子進程將要結束...')
if __name__ == '__main__':
print('父進程pid: %d' % os.getpid()) # os.getpid獲取當前進程的進程號
p = Process(target=run_proc)
p.start()
複製代碼
Process([group [, target [, name [, args [, kwargs]]]]])
target:若是傳遞了函數的引用,能夠任務這個子進程就執行這裏的代碼
args:給target指定的函數傳遞的參數,以元組的方式傳遞
kwargs:給target指定的函數傳遞命名參數
name:給進程設定一個名字,能夠不設定
group:指定進程組,大多數狀況下用不到 Process建立的實例對象的經常使用方法:
start():啓動子進程實例(建立子進程)
is_alive():判斷進程子進程是否還在活着
join([timeout]):是否等待子進程執行結束,或等待多少秒
terminate():無論任務是否完成,當即終止子進程
Process建立的實例對象的經常使用屬性:
name:當前進程的別名,默認爲Process-N,N爲從1開始遞增的整數
pid:當前進程的pid(進程號)
進程之間不共享全局變量
當須要建立的子進程數量巨大時,就能夠用到multiprocessing模塊提供的Pool方法
進程是經過導入Queue,用Queue實現多進程之間的數據傳遞,Queue自己是一個消息隊列程序。
除了可使用next()函數來喚醒生成器繼續執行外,還可使用send()函數來喚醒來執行,使用send()函數的一個好處是能夠在喚醒的同時向斷點處傳入一個附加數據
import gevent
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
複製代碼
運行結果
<Greenlet at 0x10e49f550: f(5)> 0
<Greenlet at 0x10e49f550: f(5)> 1
<Greenlet at 0x10e49f550: f(5)> 2
<Greenlet at 0x10e49f550: f(5)> 3
<Greenlet at 0x10e49f550: f(5)> 4
<Greenlet at 0x10e49f910: f(5)> 0
<Greenlet at 0x10e49f910: f(5)> 1
<Greenlet at 0x10e49f910: f(5)> 2
<Greenlet at 0x10e49f910: f(5)> 3
<Greenlet at 0x10e49f910: f(5)> 4
<Greenlet at 0x10e49f4b0: f(5)> 0
<Greenlet at 0x10e49f4b0: f(5)> 1
<Greenlet at 0x10e49f4b0: f(5)> 2
<Greenlet at 0x10e49f4b0: f(5)> 3
<Greenlet at 0x10e49f4b0: f(5)> 4
複製代碼
3個greenlet是依次運行而不是交替運行,能夠導入time,添加延時切換執行
Python中遇到recv、accept、等語句時,是默認阻塞的,即若是不設置一些條件時,程序會一直等待下去。
而非阻塞就是經過設置條件,把阻塞變爲非阻塞,因此轉變語法須要在阻塞以前設置
例:server_socket.setblocking(False)
複製代碼
請求包括:請求頭、請求體、請求行
響應包括:響應頭、響應行、響應體
短鏈接就是創建鏈接、接收數據、關閉鏈接,每次只獲取1次數據
長鏈接就是創建鏈接後,屢次請求,直到沒有請求後關閉的鏈接
TCP通訊的整個過程
四次揮手:客戶端調用close時,向服務器發送請求,服務器迴應請求同時解堵塞,調用本身close後,再次向客戶端發送close請求,此時客戶端方會等待兩個最大報文時間,等待接收服務器的請求(等待是爲了不斷網,斷電等特殊狀況),收到服務器的請求後,向服務器迴應請求,服務器收到請求後關閉,4次揮手成功,雙方關閉鏈接