首先,先從多任務講起:
現代操作系統(Windows、Mac OS X、Linux、UNIX等)都支持"多任務"
什麼叫多任務???
操作系統同時可以運行多個任務
早期電腦都是單核cpu,他執行任務原理:
操作系統輪流讓各個任務交替執行,QQ執行2Us,切換到微信,執行2Us,
再切換到陌陌,執行2Us,……。表面上看,每個任務反覆執行下去,但是CPU調度
執行太快了,導致我們感覺就像所有任務都在同時執行一樣。
現在是多核CPU實現多任務原理:
真正的並行執行多任務只能在多核CPU上實現,但是由於任務數量遠遠多於CPU核心數量
所以,操作系統也會自動把很多任務輪流調度到每個核心上的執行
併發:看上去一起執行,任務數多於核心數
並行:真正一起執行,任務數小於等於CPU核心數
實現多任務的方式:
1、多進程模式
2、多線程模式(常用)
3、協程模式(在開發中,很少用)
4、多進程+多線程 模式
接下來講講進程:
任務管理器:裏面都是進程
對於操作系統而言,一個任務就是一個進程
進程是系統中程序執行和資源分配的基本單位,每個進程都有自己的數據段(存儲數據),
代碼段(存儲代碼)、和堆(存儲一些對象的)棧(普通的變量就在棧上)段。
進程的目的:實現多任務,提高我們的執行效率
進程: 就是創建一個任務,讓它去執行其他的功能
===============================================================================
from time import sleep
def run():
while True:
print("sunck is a nice man")
sleep(1.2)
if __name__ == '__main__':
while True:
print("sunck is a good man")
sleep(1)
# 不會執行 run 方法,只有上面的while循環結束纔可以執行
# 要讓這個兩個任務同時執行,就是多任務
run()
運行結果:
sunck is a good man
sunck is a good man
sunck is a good man
sunck is a good man
sunck is a good man
sunck is a good man
===============================================================================
multiprocessing 庫
multiple: adj.數量多的;多種多樣的;
n.倍數;
processing: v.處理;加工;
n.過程;加工處理;處置;進行;
adj.經過特殊加工的;(用化學方法等)處理過的;
在linux下可以使用C語言的方法fork實現多進程,但是它不支持window,
但是這個三方庫multiprocessing庫是一個跨平臺版本的多進程模塊
提供了一個Process類來代表一個進程對象
所以我們要使用多進程就要引入multiprocessing庫
import os
from multiprocessing import Process
from time import sleep
# 子進程需要執行的代碼
def run(adj):
# os.getpid() 獲取當前進程ID號
# os.getppid() 獲取當前進程的父進程ID號
while True:
print("sunck is a %s man--%s--%s"%(adj, os.getpid(),os.getppid()))
sleep(1.2)
if __name__ == '__main__':
print("主(父)進程啓動")
# os.getpid() 獲取當前父進程ID號
print(os.getpid())
# 創建一個子進程(在父進程下創建一個進程,故稱爲該進程的子進程)
p = Process(target=run, args=("nice",))
# target:說明 該子進程要執行的任務、代碼、函數
# args:可以給target的函數傳參數,是一個元組類型,單個參數要加逗號,
# 啓動進程
p.start()
while True:
print("sunck is a good man")
sleep(1)
運行結果:
主(父)進程啓動
1975
sunck is a good man
sunck is a nice man--1976--1975
sunck is a good man
sunck is a nice man--1976--1975
===============================================================================
'''全局變量在多個進程中是不能共享的'''
from multiprocessing import Process
from time import sleep
NUM = 100
def run():
print("子進程開始")
global NUM
NUM += 1
print(NUM)
print("子進程結束")
if __name__ == '__main__':
print("父進程開始")
p = Process(target=run)
p.start()
p.join()
print(NUM)
# 在子進程中修改全局變量對父進程中的全局變量沒有影響
# 爲什麼沒影響呢?因爲他在創建子進程時,對全局變量做了一個備份,父進程中的與子進程中的
# NUM是兩個完全不同的變量
print("父進程結束--%d" % NUM)
運行結果:
父進程開始
子進程開始
101
子進程結束
100
父進程結束--100
# 父子進程的先後執行順序
from multiprocessing import Process
from time import sleep
def run(args):
print("子進程啓動")
sleep(3)
print("子進程結束")
if __name__ == '__main__':
print("主(父)進程啓動")
p = Process(target=run, args=("nice",))
p.start()
# 父進程的結束不能影響子進程,讓父進程等待子進程,再執行父進程
p.join()
print("父進程結束")
'''
進程池
'''
import os
import time
import random
# 爲了對多個進程好管理,使用進程池
# from multiprocessing import Process
from multiprocessing import Pool
def run(name):
print('子進程%s啓動--%s' % (name, os.getpid()))
strat = time.time()
time.sleep(random.choice([1, 2, 3]))
end = time.time()
print('子進程%s結束--%s--耗時%.2f' % (name, os.getpid(), end-strat))
if __name__ == '__main__':
print('父進程啓動')
# 創建多個進程
# 進程池
# 4:表示可以同時執行的進程數量
# 參數可以寫,pool默認大小是CPU核心數
pp = Pool(4)
# 創建進程,創建的進程數要大於CPU核心數,這樣才能體驗到多進程的效果
# 這裏因爲進程都是幹一樣的活,所以使用for循環創建進程
# 子進程的執行數據是沒有順序的。
for i in range(5):
# 創建進程,放進進程池,統一管理
pp.apply_async(run, args=(i,))
'''
如果每個進程乾的活不一樣,那就單獨創建每一個進程,不要寫for循環。
例:
pp.apply_async(func1, agrs=())
pp.apply_async(func2, agrs=())
pp.apply_async(func3, agrs=())
pp.apply_async(func4, agrs=())
pp.apply_async(func5, agrs=())
'''
# 在調用join之前,必須先調用close,並且在調用close之後,就不能再繼續添加新的進程了
pp.close()
# 進程池對象調用的join,會等待進程池中的所有的子進程結束完畢,再去執行父進程。
pp.join()
print("父進程結束")
'''
運行結果: 這裏進程看似0,1,2,3啓動的,實際上,進程啓動是沒有順序的。
父進程啓動
子進程0啓動--5251
子進程1啓動--5252
子進程2啓動--5253
子進程3啓動--5254
子進程2結束--5253--耗時1.00
子進程0結束--5251--耗時1.00
子進程4啓動--5253
子進程3結束--5254--耗時1.00
子進程1結束--5252--耗時2.00
子進程4結束--5253--耗時3.00
父進程結束
'''
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 多進程實現文件拷貝
import os
import time
from multiprocessing import Pool
# 實現文件的拷貝
def copy_file(read_file_path, write_file_path):
read_file = open(read_file_path, 'rb')
write_file = open(write_file_path, 'wb')
context = read_file.read()
write_file.write(context)
read_file.close()
write_file.close()
path = r''
to_path = r''
if __name__ == '__main__':
# 讀取path下的所有文件
file_list = os.listdir(path)
start = time.time()
pp = Pool(2)
for file_name in file_list:
pp.apply_async(copy_file,
args=(os.path.join(path, file_name),
os.path.join(to_path, file_name)
)
)
pp.close()
pp.join()
end = time.time()
run_time = end - start
print('總耗時---%d' % run_time)
#二次封裝的文件名,一般是:自己的名字+第三方庫的名稱
import os
import time
from multiprocessing import Process
class SunckProcess(Process):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
super().run()
print('子進程(%s-%s)啓動' % (self.name, os.getpid()))
# 子進程的功能
time.sleep(3)
print('子進程(%s-%s)結束' % (self.name, os.getpid()))
==================================================================
from sunckProcess import SunckProcess
if __name__ == '__main__':
print('父進程啓動')
# 創建子進程
p = SunckProcess('test')
# 在這裏不要調用進程裏面的run方法,調用它的start就會自動調用進程對象的run方法
p.start()
p.join()
print("父進程結束")