分享一個自己封裝且一直在維護的依賴.net4.5的http非同步組包工具類(支援get,post( 表單 ,json, 包含圖片等檔案的流提交) ,cookie管理,自動跳轉,代理IP,https的支援,高併發的配置等等
一:程序理論
1.程式 和 程序
程式 就是一堆程式碼檔案,是指令和資料的集合,可以作為目標檔案儲存在磁碟中,或者作為段存放在記憶體地址空間中。(靜態)
程序 就是一個程式執行的過程,是作業系統進行資源分配和保護的基本單位。(動態)
1個程式可以對應多個程序,但1個程序只能對應1個程式。程序和程式的關係猶如演出和劇本的關係。
2.併發、並行、序列
序列:多個任務依次執行、一個程序執行完畢,再執行下一個
並行:多個任務是真正意義上一起執行,只有多個CPU才能並行的概念,
併發:多個任務看起來是同時執行的,本質上還是一個個地執行
3.同步 - 非同步 / 阻塞 - 非阻塞
同步(慢):
發起一個請求,直到請求返回結果之後,才進行下一步操作。
就像執行一段程式碼,自上而下一行一行執行,只有上一行程式碼執行完畢,才能執行下一行程式碼。
簡單來說,同步就是:必須一件事一件事的做,等前一件做完了,才能做下一件事。
非同步(快):
發起一個請求後,不管這個請求有沒有返回結果,直接可以進行下一步操作。
一般情況下,有一個回撥
操作。
簡單來說,非同步就是:可以多件事同時做。
阻塞(慢):
遇到了IO操作,CPU會被作業系統切換到其他程序。
呼叫結果返回之前,當前執行緒會被掛起。呼叫執行緒只有在得到結果之後才會返回。
簡單來說,阻塞就是:需要買奶茶和冰淇淋,買奶茶的時候奶茶製作過程中只能等,然後買完奶茶再去買冰淇淋。
非阻塞(快):
沒有IO操作,一直在執行。
在不能立刻得到結果之前,該呼叫不會阻塞當前執行緒。
簡單來說,非阻塞就是:需要買奶茶和冰淇淋,買奶茶的時候等的時間去買冰淇淋。
最佳狀態:非同步 + 非阻塞
拓展:
同步框架:Flask、Django3.0之前
非同步框架:Tornado、Sanic、FastAPI
例子:
背景:媽媽出門了,小明想要看電視,但是媽媽讓小明燒水。
1.小明燒水,在一旁等待,時不時看一下水有沒有燒開。 —— 同步阻塞
2.小明燒水,等待的時間偷偷去看會兒電視,看電視的時候時不時來看一下水有沒有燒開。 —— 同步非阻塞
3.小明買了一個水開了之後會響的水壺來燒水,燒水時在一旁等著,不用時不時看水有木有燒開。 —— 非同步阻塞
4.小明用那個會響的水壺燒水,然後去看電視,等水開了之後發出響聲,再去開。 —— 非同步非阻塞
4.程序執行的三種狀態
開啟一個應用程式,該程序會進入
就緒態
,獲取CPU資源後,執行程式程式碼,進入執行態
,出現了讀寫檔案with open(...)
的IO操作的時候,會進入阻塞態
,CPU資源就會被作業系統分配到其他程序。
執行態(Running)(非阻塞):程序已獲CPU,正在執行。單處理機系統中,處於執行狀態的程序只一個;多處理機系統中,有多個處於執行狀態的程序。
就緒態(Ready)(非阻塞):程序已獲得除CPU外的所有必要資源,只等待CPU時的狀態。一個系統會將多個處於就緒狀態的程序排成一個就緒佇列。
阻塞態(Blocked)(阻塞):正在執行的程序由於某種原因(檔案讀寫等IO操作)而暫時無法繼續執行,便放棄處理機而處於暫停狀態,即程序執行受阻。(這種狀態又稱等待狀態或封鎖狀態)
就緒 → 執行
處於就緒狀態的程序,當程序排程程式為之分配了處理機後,該程序便由就緒狀態轉變成執行狀態。
執行 → 就緒
處於執行狀態的程序在其執行過程中,因分配給它的一個時間片已用完而不得不讓出處理機,於是程序從執行狀態轉變成就緒狀態。
執行 → 阻塞
正在執行的程序因等待某種事件(檔案讀寫等IO操作)發生而無法繼續執行時,便從執行狀態變成阻塞狀態。
阻塞 → 就緒
處於阻塞狀態的程序,若其等待的事件已經發生,於是程序由阻塞狀態轉變為就緒狀態。
優化程式效率的核心法則
降低IO操作(硬碟IO、網路IO)
資料獲取優先順序:
記憶體 > 本地硬碟 > 網路IO
5.提交任務的2種方式
同步呼叫:一個任務必須要執行完畢才能執行另一個任務
非同步呼叫:一個任務在執行過程中,可以執行另一個任務
二:程序的使用
1.程序的建立
Windows:CreateProcess
Linux:Fork
Windows中檢視某個程序
tasklist |findstr python
2.程序的終止
1.正常退出(自願;程式執行完畢後,終止,資源被回收)
2.出錯退出(自願;python3 test.py
但是test.py
不存在)
3.嚴重錯誤(非自願;執行非法指令)
4.被其他程序殺死(非自願;被作業系統殺死taskkill /F /PID 3333
)
三:實戰
0.試試就逝世
import time
from multiprocessing import Process
def task(n):
print('%s run' % n)
time.sleep(10000)
if __name__ == '__main__':
for i in range(10000):
p = Process(target=task, args=(1,))
p.start()
print('主程序')
1.單個父程序 + 單個子程序
import os
import time
from multiprocessing import Process
def task(n):
print(f'task[{os.getpid()}] is running')
time.sleep(n)
print(f'task[{os.getpid()}] is done')
if __name__ == '__main__':
# p = Process(target=task, args=(5,)) # args中為元組/列表
p = Process(target=task, kwargs={'n': 5}) # kwargs中為字典
p.start() # 在向發作業系統傳送啟動子程序的訊號,屬於IO操作,速度慢
print(f'主程序[{os.getpid()}]')
# 主程序[15188]
# task[86956] is running
# task[86956] is done
2.單個父程序 + 多個子程序 方式1
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
p1 = Process(target=task, args=(2, 'p1'))
p2 = Process(target=task, args=(2, 'p2'))
p3 = Process(target=task, args=(2, 'p3'))
p1.start() # 在向發作業系統傳送啟動子程序的訊號,屬於IO操作,速度慢
p2.start() # 在向發作業系統傳送啟動子程序的訊號,屬於IO操作,速度慢
p3.start() # 在向發作業系統傳送啟動子程序的訊號,屬於IO操作,速度慢
print(f'主程序[{os.getpid()}]')
# 主程序[79800]
# task[p1] is running [17320]
# task[p3] is running [66276]
# task[p2] is running [36784]
# task[p1] is done [17320]
# task[p3] is done [66276]
# task[p2] is done [36784]
3.單個父程序 + 多個子程序 方式2
import os
import time
from multiprocessing import Process
class Myprocess(Process):
def __init__(self, tag):
super().__init__()
self.tag = tag
def run(self) -> None: # 表示run函式的返回值為空,無返回值
print(f'task[{self.tag}] is running [{os.getpid()}]')
time.sleep(3)
print(f'task[{self.tag}] is done [{os.getpid()}]')
if __name__ == '__main__':
p1 = Myprocess('程序1')
p2 = Myprocess('程序2')
p3 = Myprocess('程序3')
p1.start() # 相當於:p1.run,但是p1.run是同步的,所以這裡用p1.start
p2.start() # p2.run
p3.start() # p3.run
print(f'主程序[{os.getpid()}]')
4.程序之間的資料是隔離的
import os
import time
from multiprocessing import Process
age = 18
def task(n, name):
global age # 區域性修改全域性
age = 99
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
print(f'子程序的age:{age}')
if __name__ == '__main__':
p1 = Process(target=task, args=(1, 'p1'))
p1.start()
print(f'主程序[{os.getpid()}]')
print(f'主程序的age:{age}')
# 主程序[2680]
# 主程序的age:18
# task[p1] is running [45116]
# task[p1] is done [45116]
# 子程序的age:99
5.join - 讓子程序的開啟者 等p1開啟並執行完畢後 再執行
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
p1 = Process(target=task, args=(2, 'p1'))
p1.start() # 在向發作業系統傳送啟動子程序的訊號,屬於IO操作,速度慢
p1.join() # join讓子程序執行完成
print(f'主程序[{os.getpid()}]')
# task[p1] is running [47164]
# task[p1] is done [47164]
# 主程序[44356]
不用join - 不等待 耗時0.幾秒
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
ctime = time.time()
p1 = Process(target=task, args=(1, 'p1'))
p2 = Process(target=task, args=(2, 'p1'))
p1.start()
p2.start()
# p1.join()
# p2.join()
print(f'主程序[{os.getpid()}]')
print(time.time() - ctime)
# 不用join
# 主程序[59116]
# 0.020940065383911133
# task[p1] is running [89420]
# task[p1] is running [91328]
# task[p1] is done [89420]
# task[p1] is done [91328]
只用p1.join - 等待p1執行完畢再執行主程序
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
ctime = time.time()
p1 = Process(target=task, args=(1, 'p1'))
p2 = Process(target=task, args=(2, 'p2'))
p1.start()
p2.start()
p1.join()
# p2.join()
print(f'主程序[{os.getpid()}]')
print(time.time() - ctime)
# 只用p1.join
# task[p1] is running [61892]
# task[p2] is running [38660]
# task[p1] is done [61892]
# 主程序[47172]
# 1.1537489891052246
# task[p2] is done [38660]
只用p2.join - 等待p2執行完畢再執行主程序
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
ctime = time.time()
p1 = Process(target=task, args=(1, 'p1'))
p2 = Process(target=task, args=(2, 'p2'))
p1.start()
p2.start()
# p1.join()
p2.join()
print(f'主程序[{os.getpid()}]')
print(time.time() - ctime)
# 只用p2.join
# task[p1] is running [56056]
# task[p2] is running [47384]
# task[p1] is done [56056]
# task[p2] is done [47384]
# 主程序[3424]
# 2.159543514251709
同時p1.join和p2.join - 時間取決於最長的那個
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
ctime = time.time()
p1 = Process(target=task, args=(1, 'p1'))
p2 = Process(target=task, args=(2, 'p2'))
p1.start()
p2.start()
p1.join()
p2.join()
print(f'主程序[{os.getpid()}]')
print(time.time() - ctime)
# p1.join + p2.join
# task[p1] is running [56056]
# task[p2] is running [47384]
# task[p1] is done [56056]
# task[p2] is done [47384]
# 主程序[3424]
# 2.159543514251709
6.join - 執行多個子程序 - 序列
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
p1 = Process(target=task, args=(2, 'p1'))
p2 = Process(target=task, args=(3, 'p2'))
p3 = Process(target=task, args=(4, 'p3'))
start = time.time()
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
print(f'主程序[{os.getpid()}]')
print('耗時:', time.time() - start)
# task[p1] is running [72452]
# task[p1] is done [72452]
# task[p2] is running [31540]
# task[p2] is done [31540]
# task[p3] is running [62568]
# task[p3] is done [62568]
# 主程序[11548]
# 耗時: 9.440884351730347
7.join - 執行多個子程序 - 併發
import os
import time
from multiprocessing import Process
def task(n, name):
print(f'task[{name}] is running [{os.getpid()}]')
time.sleep(n)
print(f'task[{name}] is done [{os.getpid()}]')
if __name__ == '__main__':
p1 = Process(target=task, args=(2, 'p1'))
p2 = Process(target=task, args=(3, 'p2'))
p3 = Process(target=task, args=(4, 'p3'))
start = time.time()
p1.start()
p2.start()
p3.start()
p1.join() # 此時,p1、p2、p3的join順序已經不重要了
p2.join()
p3.join()
print(f'主程序[{os.getpid()}]')
print('耗時:', time.time() - start)
# task[p2] is running [47248]
# task[p3] is running [46152]
# task[p1] is running [43612]
# task[p1] is done [43612]
# task[p2] is done [47248]
# task[p3] is done [46152]
# 主程序[3776]
# 耗時: 4.173335313796997