進(jìn)程
進(jìn)程的概念
python中的多線程其實(shí)并不是真正的多線程,如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多進(jìn)程。
進(jìn)程的概念:
進(jìn)程是程序的一次執(zhí)行過程, 正在進(jìn)行的一個(gè)過程或者說一個(gè)任務(wù),而負(fù)責(zé)執(zhí)行任務(wù)的則是CPU.
進(jìn)程的生命周期:
當(dāng)操作系統(tǒng)要完成某個(gè)任務(wù)時(shí),它會創(chuàng)建一個(gè)進(jìn)程。當(dāng)進(jìn)程完成任務(wù)之后,系統(tǒng)就會撤銷這個(gè)進(jìn)程,收回它所占用的資源。從創(chuàng)建到撤銷的時(shí)間段就是進(jìn)程的生命期
進(jìn)程之間存在并發(fā)性:
在一個(gè)系統(tǒng)中,同時(shí)會存在多個(gè)進(jìn)程。他們輪流占用CPU和各種資源
并行與并發(fā)的區(qū)別:
無論是并行還是并發(fā),在用戶看來都是同時(shí)運(yùn)行的,不管是進(jìn)程還是線程,都只是一個(gè)任務(wù)而已,
真正干活的是CPU,CPU來做這些任務(wù),而一個(gè)cpu(單核)同一時(shí)刻只能執(zhí)行一個(gè)任務(wù)。
并行:多個(gè)任務(wù)同時(shí)運(yùn)行,只有具備多個(gè)cpu才能實(shí)現(xiàn)并行,含有幾個(gè)cpu,也就意味著在同一時(shí)刻可以執(zhí)行幾個(gè)任務(wù)。
并發(fā):是偽并行,即看起來是同時(shí)運(yùn)行的,實(shí)際上是單個(gè)CPU在多道程序之間來回的進(jìn)行切換。
同步與異步的概念:
同步就是指一個(gè)進(jìn)程在執(zhí)行某個(gè)請求的時(shí)候,若該請求需要一段時(shí)間才能返回信息,那么這個(gè)進(jìn)程將會一直等待下去,直到收到返回信息才繼續(xù)執(zhí)行下去。
異步是指進(jìn)程不需要一直等下去,而是繼續(xù)執(zhí)行下面的操作,不管其他進(jìn)程的狀態(tài)。當(dāng)有消息返回時(shí)系統(tǒng)會通知進(jìn)行處理,這樣可以提高執(zhí)行的效率。
比如:打電話的過程就是同步通信,發(fā)短信時(shí)就是異步通信。
多線程和多進(jìn)程的關(guān)系:
對于計(jì)算密集型應(yīng)用,應(yīng)該使用多進(jìn)程;
對于IO密集型應(yīng)用,應(yīng)該使用多線程。線程的創(chuàng)建比進(jìn)程的創(chuàng)建開銷小的多。
創(chuàng)建進(jìn)程
使用multiprocessing.Process
import multiprocessing
import time
def func(arg):
pname = multiprocessing.current_process().name
pid = multiprocessing.current_process().pid
print("當(dāng)前進(jìn)程ID=%d,name=%s" % (pid, pname))
for i in range(5):
print(arg)
time.sleep(1)
if __name__ == "__main__":
p = multiprocessing.Process(target=func, args=("hello",))
# p.daemon = True # 設(shè)為【守護(hù)進(jìn)程】(隨主進(jìn)程的結(jié)束而結(jié)束)
p.start()
while True:
print("子進(jìn)程是否活著?", p.is_alive())
time.sleep(1)
print("main over")
通過繼承Process實(shí)現(xiàn)自定義進(jìn)程
import multiprocessing
import os
# 通過繼承Process實(shí)現(xiàn)自定義進(jìn)程
class MyProcess(multiprocessing.Process):
def __init__(self, name, url):
super().__init__()
self.name = name
self.url = url # 自定義屬性
# 重寫run
def run(self):
pid = os.getpid()
ppid = os.getppid()
pname = multiprocessing.current_process().name
print("當(dāng)前進(jìn)程name:", pname)
print("當(dāng)前進(jìn)程id:", pid)
print("當(dāng)前進(jìn)程的父進(jìn)程id:", ppid)
if __name__ == '__main__':
# 創(chuàng)建3個(gè)進(jìn)程
MyProcess("小分隊(duì)1", "").start()
MyProcess("小分隊(duì)2", "").start()
MyProcess("小分隊(duì)3", "").start()
print("主進(jìn)程ID:", multiprocessing.current_process().pid)
# CPU核數(shù)
coreCount = multiprocessing.cpu_count()
print("我的CPU是%d核的" % coreCount)
# 獲取當(dāng)前活動的進(jìn)程列表
print(multiprocessing.active_children())
同步異步和進(jìn)程鎖
import multiprocessing
import random
import time
def fn():
name = multiprocessing.current_process().name
print("開始執(zhí)行進(jìn)程:", name)
time.sleep(random.randint(1, 4))
print("執(zhí)行結(jié)束:", name)
# 多進(jìn)程
# 異步執(zhí)行進(jìn)程
def processAsync():
p1 = multiprocessing.Process(target=fn, name="小分隊(duì)1")
p2 = multiprocessing.Process(target=fn, name="小分隊(duì)2")
p1.start()
p2.start()
# 同步執(zhí)行
def processSync():
p1 = multiprocessing.Process(target=fn, name="小分隊(duì)1")
p2 = multiprocessing.Process(target=fn, name="小分隊(duì)2")
p1.start()
p1.join()
p2.start()
p2.join()
# 加鎖
def processLock():
# 進(jìn)程鎖
lock = multiprocessing.Lock()
p1 = multiprocessing.Process(target=fn2, name="小分隊(duì)1", args=(lock,))
p2 = multiprocessing.Process(target=fn2, name="小分隊(duì)2", args=(lock,))
p1.start()
p2.start()
def fn2(lock):
name = multiprocessing.current_process().name
print("開始執(zhí)行進(jìn)程:", name)
# 加鎖
# 方式一
# if lock.acquire():
# print("正在工作...")
# time.sleep(random.randint(1, 4))
# lock.release()
# 方式二
with lock:
print("%s:正在工作..." % name)
time.sleep(random.randint(1, 4))
print("%s:執(zhí)行結(jié)束:"% name)
if __name__ == '__main__':
# processAsync() # 異步執(zhí)行
# processSync() # 同步執(zhí)行
processLock() # 加進(jìn)程鎖
使用Semaphore控制進(jìn)程的最大并發(fā)
import multiprocessing
import time
def fn(sem):
with sem:
name = multiprocessing.current_process().name
print("子線程開始:", name)
time.sleep(3)
print("子線程結(jié)束:", name)
if __name__ == '__main__':
sem = multiprocessing.Semaphore(3)
for i in range(8):
multiprocessing.Process(target=fn, name="小分隊(duì)%d"%i, args=(sem, )).start()
matplotlib
matplotlib介紹和簡單使用
Matplotlib是什么
Matplotlib 是一個(gè) Python 的 2D繪圖庫
通過 Matplotlib,開發(fā)者可以僅需要幾行代碼,便可以生成繪圖,直方圖,功率譜,條形圖,錯(cuò)誤圖,散點(diǎn)圖等。
Matplotlib的簡單使用
import matplotlib
from matplotlib import pyplot as plt
# 顯示中文
# 配置字體
matplotlib.rcParams['font.sans-serif'] = ['simhei']
matplotlib.rcParams['font.family'] = 'sans-serif'
# 畫線
# plt.plot([1,2], [3,5])
# plt.plot([1,3,7], [2,5,8])
# plt.plot([1,3,7], [2,5,8], '--') # 虛線
# xy軸文字
plt.xlabel('x軸')
plt.ylabel('y軸')
# 參數(shù)x:x軸位置
# 參數(shù)height:高度
# 參數(shù)width:默認(rèn)0.8
plt.bar([1], [123], label='bj')
plt.bar([3], [245], label='sz')
plt.legend() # 繪制
# plt.show() # 顯示
plt.savefig('line') # 保存圖片
練習(xí):爬取51job不同職位的崗位數(shù)量,并用折線圖和條形圖表示出來
url = "https://search.51job.com/list/000000,000000,0000,00,9,99,%s,2,1.html" % job
擴(kuò)展
線程池
import threading
import threadpool
import time
import random
# ================================================================= #
def fn(who):
tname = threading.current_thread().getName()
print("%s開始%s..." % (tname, who))
time.sleep(random.randint(1, 5))
print("-----%s,%s-----" % (tname, who))
# ================================================================= #
# 請求執(zhí)行結(jié)束回調(diào)
# request=已完成的請求
# result=任務(wù)的返回值
def cb(request, result):
print("cb", request, result)
if __name__ == '__main__':
# 創(chuàng)建一個(gè)最大并發(fā)為4的線程池(4個(gè)線程)
pool = threadpool.ThreadPool(4)
argsList = ["張三豐", "趙四", "王五", "六爺", "洪七公", "朱重八"]
# 允許回調(diào)
requests = threadpool.makeRequests(fn, argsList, callback=cb)
for req in requests:
pool.putRequest(req)
# 阻塞等待全部請求返回(線程池創(chuàng)建的并發(fā)默認(rèn)為【守護(hù)線程】)
pool.wait()
print("Over")
進(jìn)程池
import multiprocessing
import random
import time
def fn1(arg, name):
print("正在執(zhí)行任務(wù)1: {}...".format(arg))
time.sleep(random.randint(1, 5))
print("進(jìn)程%d完畢!" % (name))
def fn2(arg, name):
print("正在執(zhí)行任務(wù)2: {}...".format(arg))
time.sleep(random.randint(1, 5))
print("進(jìn)程%d完畢!" % (name))
# 回調(diào)函數(shù)
def onback(result):
print("得到結(jié)果{}".format(result))
if __name__ == "__main__":
# 待并發(fā)執(zhí)行的函數(shù)列表
funclist = [fn1, fn2, fn1, fn2]
# 創(chuàng)建一個(gè)3并發(fā)的進(jìn)程池
pool = multiprocessing.Pool(3)
# 遍歷函數(shù)列表,將每一個(gè)函數(shù)丟入進(jìn)程池中
for i in range(len(funclist)):
# 同步執(zhí)行
# pool.apply(func=funclist[i], args=("hello", i))
# 異步執(zhí)行
pool.apply_async(func=funclist[i], args=("hello", i), callback=onback)
pool.close() # 關(guān)閉進(jìn)程池,不再接收新的進(jìn)程
pool.join() # 令主進(jìn)程阻塞等待池中所有進(jìn)程執(zhí)行完畢