1. 程式人生 > 實用技巧 >分享一個自己封裝且一直在維護的依賴.net4.5的http非同步組包工具類(支援get,post( 表單 ,json, 包含圖片等檔案的流提交) ,cookie管理,自動跳轉,代理IP,https的支援,高併發的配置等等

分享一個自己封裝且一直在維護的依賴.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