多任務
生活中的多任務:
有很多的場景中的事情是同時進行的,例如
1.開車的時候 手和腳共同來駕駛汽車,還一邊聽着音樂
2.再比如唱歌跳舞也是同時進行的;....
程序中的多任務
# 喫飯
def eat():
for i in range(3):
print("喫飯..", i)
yield None
# 打電話
def call_up():
for i in range(3):
print("打電話..", i)
yield None
if __name__ == "__main__":
e = eat()
c = call_up()
try:
while True:
e.__next__()
c.__next__()
except Exception as result:
print(result)
#結果
# 喫飯.. 0
# 打電話.. 0
# 喫飯.. 1
# 打電話.. 1
# 喫飯.. 2
# 打電話.. 2
如果有多件事情是同時進行,我們把這種情況叫做多任務。Linux 是真正的多任務、多用戶操作系統,windows是多任務操作系統,但不是真正意義上的多用戶操作系統。
多任務在程序中的實現--進程和線程
當多任務操作系統使用某種任務調度策略允許兩個或更多進程併發共享一個處理器時,事實上處理器在某一時刻只會給一件任務提供服務。因爲任務調度機制保證不同任務之間的切換速度十分迅速,因此給人多個任務同時運行的錯覺。多任務系統中有3個功能單位:任務、進程和線程;
併發:兩個或多個事件在同一時間間隔內發生
並行:兩個或多個事件在同一時刻發生
多任務:(進程)操作系統可以同時運行多個任務
os.fork函數創建進程
Python的os模塊封裝了常見的系統調用,前面我們使用os模塊中的os.mkdir()創建目錄,其中就包括os.fork(),可以在Python程序中輕鬆創建子進程,並且實現多任務,但是在windows上無法創建成功。
import os
import time
print("-----11111----")
pid = os.fork() # 返回值: ==0 子進程 >0 父進程
print("----22222----")
if pid == 0:
print("-----33333---")
print("子進程:pid:", pid)
elif pid > 0:
time.sleep(0.1)
print("-----44444---")
print("父進程:pid:", pid)
else:
print("-----55555---")
print("創建進程失敗!")
總結:
1.代碼從上往下執行到os.fork()時,python的會調用操作系統會創建一個新的進程(子進程),然後複製父進程的所有信息到子進程中,然後父進程和子進程都會從fork()函數中得到一個返回值,在子進程中這個值一定是0,而父進程中返回的是剛好子進程的 id號。
2.在Unix/Linux(windows不支持)操作系統中,提供了一個fork()系統函數,它非常特殊。普通的函數調用,調用一次,返回一次,但是fork()調用一次,返回兩次,因爲操作系統自動把當前進程(稱爲父進程)複製了一份(稱爲子進程),然後,分別在父進程和子進程內返回。
3.子進程永遠返回0,而父進程返回子進程的ID,這樣做的理由是,一個父進程可以fork出很多子進程,所以,父進程要記下每個子進程的ID,而子進程只需要調用getppid()就可以拿到父進程的ID,getpid()得到當前進程的ID。
4. 父進程和子進程那個先執行:這個跟操作系統調度有關,不一定那個先執行。
5. Linux創建進程最多達到65535個,進程號不能相同的,如果已經存在,就往後去找對應的數做進程號,最多端口也是和進程創建數也差不多,一個進程對應有一個端口號。
進程之間的數據不共享
import os
import time
count = 0
number = 100
print("-----11111----")
pid = os.fork()
class Person:
pass
person = Person() # person就是對象類型
if pid == 0:
for i in range(5):
count += 1
number -= 1
person.name = "小黑-子"
print("子進程中count的值:%d,number的值:%d,Person對象:%s" % (id(count), id(number), id(person)))
elif pid > 0:
for i in range(5):
count += 1
number -= 1
person.name = "小白-父"
time.sleep(1)
print("父進程中count的值:%d,number的值:%d,Person對象:%s" % (id(count), id(number), id(person)))
else:
print("---game over--")
print(pid, "====>", person.name)
多進程中,每個進程中所有數據(包括全局變量)都各有擁有一份,互不影響。
fork時子進程獲得父進程代碼和數據段、共享庫、堆和棧的拷貝,所以變量的地址也是一樣的,並且在某一個進程中修改相同變量的值,在另外一個進程中的相同變量的值不會修改。