進程與線程
操作系統
1.為什麽要有操作系統
操作系統,位於底層硬件與應用軟件之間的一層
工作方式:向下管理硬件,向上提供接口
操作系統進程切換:
1.出現IO操作
2.固定時間
進程
1.定義
進程就是一個程序在一個數據集上的一次動態執行過程。進程一般由程序、數據集、進程控制塊三部分組成。我們編寫的程序用來描述進程要完成哪些功能以及如何完成;數據集則是程序在執行過程中所需要使用的資源;進程控制塊用來記錄進程的外部特征,描述進程的執行變化過程,系統可以利用它來控制和管理進程,它是系統感知進程存在的唯一標誌。
進程由三部分組成:
1、程序:我們編寫的程序用來描述進程要完成哪些功能以及如何完成
2、數據集:數據集則是程序在執行過程中所需要使用的資源
3、進程控制塊:進程控制塊用來記錄進程的外部特征,描述進程的執行變化過程,系統可以利用它來控制和管理進程,它是系統感
知進程存在的唯一標誌。
線程
線程的出現是為了降低上下文切換的消耗,提高系統的並發性,並突破一個進程只能幹一樣事的缺陷,使到進程內並發成為可能。線程也叫輕量級進程,它是一個基本的CPU執行單元,也是程序執行過程中的最小單元,由線程ID、程序計數器、寄存器集合和堆棧共同組成。線程的引入減小了程序並發執行時的開銷,提高了操作系統的並發性能。線程沒有自己的系統資源。
Threading用於提供線程相關的操作。線程是應用程序中工作的最小單元,它被包含在進程之中,是進程中的實際運作單位。一
條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務。
進程與線程的關系
進程是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。或者說進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
線程則是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。
進程和線程的關系:
(1)一個線程只能屬於一個進程,而一個進程可以有多個線程,但至少有一個線程。
(2)資源分配給進程,同一進程的所有線程共享該進程的所有資源。
進程: 資源管理單位(容器)
線程: 最小執行單位
並行與並發
並行處理(Parallel Processing)是計算機系統中能同時執行兩個或更多個處理的一種計算方法。並行處理可同時工作於同一程序的不同方面。並行處理的主要目的是節省大型和復雜問題的解決時間。並發處理(concurrency Processing):指一個時間段中有幾個程序都處於已啟動運行到運行完畢之間,且這幾個程序都是在同一個處理機(CPU)上運行,但任一個時刻點上只有一個程序在處理機(CPU)上運行
並發的關鍵是你有處理多個任務的能力,不一定要同時。並行的關鍵是你有同時處理多個任務的能力。所以說,並行是並發的子集
同步與異步
在計算機領域,同步就是指一個進程在執行某個請求的時候,若該請求需要一段時間才能返回信息,那麽這個進程將會一直等待下去,直到收到返回信息才繼續執行下去;異步是指進程不需要一直等下去,而是繼續執行下面的操作,不管其他進程的狀態。當有消息返回時系統會通知進程進行處理,這樣可以提高執行的效率。舉個例子,打電話時就是同步通信,發短息時就是異步通信。
1. 實現線程並發
示例1:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading #線程 6 import time 7 8 def Hi(num): #有一個參數 9 print("hello %s" %num) 10 time.sleep(3) 11 12 if __name__ == ‘__main__‘: 13 14 t1=threading.Thread(target=Hi,args=(10,)) #創建了一個線程對象t1,10做為一個參數,傳給num 15 t1.start() 16 17 t2=threading.Thread(target=Hi,args=(9,)) #創建了一個線程對象t2,9做為一個參數,傳給num 18 t2.start() 19 20 print("ending.........") #主線程輸出ending
執行結果:
1 hello 10 #子線程 2 hello 9 #子線程 3 ending......... #主線程 4 #上面三個同時出來,再停頓三秒才結束 5 Process finished with exit code 0 #停頓3秒才結束
示例2:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 import time 7 8 def music(): 9 print("begin to listen %s"%time.ctime()) 10 time.sleep(3) 11 print("stop to listen %s" %time.ctime()) 12 13 def game(): 14 print("begin to play game %s"%time.ctime()) 15 time.sleep(5) 16 print("stop to play game %s" %time.ctime()) 17 18 if __name__ == ‘__main__‘: 19 20 t1=threading.Thread(target=music) 21 t1.start() 22 t2=threading.Thread(target=game) 23 t2.start()
執行結果:
1 #總共花了5秒時間 2 3 begin to listen Sat Jan 14 12:34:43 2017 4 begin to play game Sat Jan 14 12:34:43 2017 #1、先打印2個 5 6 stop to listen Sat Jan 14 12:34:46 2017 #2、等待3秒再打印一個 7 8 stop to play game Sat Jan 14 12:34:48 2017 #3、再等待2秒,打印一個
2.使用 join方法
示例1:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 import time 7 8 def music(): 9 print("begin to listen %s"%time.ctime()) 10 time.sleep(3) 11 print("stop to listen %s" %time.ctime()) 12 13 def game(): 14 print("begin to play game %s"%time.ctime()) 15 time.sleep(5) 16 print("stop to play game %s" %time.ctime()) 17 18 if __name__ == ‘__main__‘: 19 20 t1=threading.Thread(target=music) 21 t2=threading.Thread(target=game) 22 23 t1.start() #運行實例的方法 24 t2.start() 25 26 t1.join() #子線程對象調用join()方法 27 t2.join() 28 29 print("ending") #在主線程中
執行結果:
1 begin to listen Sat Jan 14 12:58:34 2017 2 begin to play game Sat Jan 14 12:58:34 2017 #先打印2個 3 4 stop to listen Sat Jan 14 12:58:37 2017 #等待3秒,再打印一個 5 6 stop to play game Sat Jan 14 12:58:39 2017 #等待2秒,再打印兩個 7 ending
示例2:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 import time 7 8 def music(): 9 print("begin to listen %s"%time.ctime()) 10 time.sleep(3) 11 print("stop to listen %s" %time.ctime()) 12 13 def game(): 14 print("begin to play game %s"%time.ctime()) 15 time.sleep(5) 16 print("stop to play game %s" %time.ctime()) 17 18 if __name__ == ‘__main__‘: 19 20 t1=threading.Thread(target=music) 21 t2=threading.Thread(target=game) 22 23 t1.start() #運行實例的方法 24 t2.start() 25 26 t1.join() #t1線程不結束,誰都不往下走 27 28 print("ending")
執行結果:
1 begin to listen Sat Jan 14 13:06:07 2017 2 begin to play game Sat Jan 14 13:06:07 2017 #先打印這兩行 3 4 stop to listen Sat Jan 14 13:06:10 2017 #再等待3秒打印這兩行 5 ending 6 7 stop to play game Sat Jan 14 13:06:12 2017 #再等待2秒打印這行
示例3:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 import time 7 8 def music(): 9 print("begin to listen %s"%time.ctime()) 10 time.sleep(3) 11 print("stop to listen %s" %time.ctime()) 12 13 def game(): 14 print("begin to play game %s"%time.ctime()) 15 time.sleep(5) 16 print("stop to play game %s" %time.ctime()) 17 18 if __name__ == ‘__main__‘: 19 20 t1=threading.Thread(target=music) 21 t2=threading.Thread(target=game) 22 23 t1.start() #運行實例的方法 24 t2.start() 25 26 t2.join() 27 28 print("ending") #在主線程中
執行結果:
1 begin to listen Sat Jan 14 13:12:34 2017 #先打印這兩行 2 begin to play game Sat Jan 14 13:12:34 2017 3 4 stop to listen Sat Jan 14 13:12:37 2017 #等待3秒,打印這一行 5 6 stop to play game Sat Jan 14 13:12:39 2017 #等待2秒,打印這兩行 7 ending
示例4: 並沒有實現並發(實現多線程的意義)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 import time 7 8 def music(): 9 print("begin to listen %s"%time.ctime()) 10 time.sleep(3) 11 print("stop to listen %s" %time.ctime()) 12 13 def game(): 14 print("begin to play game %s"%time.ctime()) 15 time.sleep(5) 16 print("stop to play game %s" %time.ctime()) 17 18 if __name__ == ‘__main__‘: 19 20 t1=threading.Thread(target=music) 21 t2=threading.Thread(target=game) 22 23 t1.start() 24 25 t1.join() 26 t2.start() 27 28 t2.join() 29 30 print("ending") #在主線程中
執行結果:
1 begin to listen Sat Jan 14 13:26:18 2017 #先打印條1行 2 3 stop to listen Sat Jan 14 13:26:21 2017 #等待3秒再打印2行 4 begin to play game Sat Jan 14 13:26:21 2017 5 6 stop to play game Sat Jan 14 13:26:26 2017 #等待5秒打印2行 7 ending
線程調用方法:
1.直接調用
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 import time 7 8 9 def sayhi(num): # 定義每個線程要運行的函數 10 11 print("running on number:%s" % num) 12 13 time.sleep(3) 14 15 16 if __name__ == ‘__main__‘: 17 t1 = threading.Thread(target=sayhi, args=(1,)) # 生成一個線程實例 18 t2 = threading.Thread(target=sayhi, args=(2,)) # 生成另一個線程實例 19 20 t1.start() # 啟動線程 21 t2.start() # 啟動另一個線程 22 23 print(t1.getName()) # 獲取線程名 24 print(t2.getName())
執行結果:
1 running on number:1 2 running on number:2 3 Thread-1 4 Thread-2
2.繼承式調用
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 import time 7 8 #自己定制一個MyThread的類 9 class MyThread(threading.Thread): 10 def __init__(self, num): 11 threading.Thread.__init__(self) 12 self.num = num 13 14 def run(self): # 定義每個線程要運行的函數 15 16 print("running on number:%s" % self.num) 17 18 time.sleep(3) 19 20 21 if __name__ == ‘__main__‘: 22 t1 = MyThread(1) #繼承這個類,把1這個參數,傳給num ,t1就是個線程對象 23 t2 = MyThread(2) 24 t1.start() 25 t2.start() 26 27 print("ending......")
執行結果:
1 running on number:1 2 running on number:2 3 ending......
用Daemon方法示例(設置t為守護線程,就是字線程,跟著主線程一起推出)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 from time import ctime,sleep 7 import time 8 9 def ListenMusic(name): 10 11 print ("Begin listening to %s. %s" %(name,ctime())) 12 sleep(3) 13 print("end listening %s"%ctime()) 14 15 def RecordBlog(title): 16 17 print ("Begin recording the %s! %s" %(title,ctime())) 18 sleep(5) 19 print(‘end recording %s‘%ctime()) 20 21 #創建一個列表,把t1和t2加到列表中去 22 threads = [] 23 t1 = threading.Thread(target=ListenMusic,args=(‘水手‘,)) 24 t2 = threading.Thread(target=RecordBlog,args=(‘python線程‘,)) 25 threads.append(t1) 26 threads.append(t2) 27 28 if __name__ == ‘__main__‘: 29 30 for t in threads: 31 t.setDaemon(True) #設置t為守護線程; 註意:一定在start()之前設置,否則會報錯 32 33 t.start() 34 35 print ("all over %s" %ctime())
執行結果:
1 Begin listening to 水手. Sat Jan 14 13:51:30 2017 #三個同時打印出來 2 Begin recording the python線程! Sat Jan 14 13:51:30 2017 3 all over Sat Jan 14 13:51:30 2017
示例3: 設置t1為守護線程,沒有意義,達不到效果,因為t2還會繼續執行
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 from time import ctime,sleep 7 import time 8 9 def ListenMusic(name): 10 11 print ("Begin listening to %s. %s" %(name,ctime())) 12 sleep(3) 13 print("end listening %s"%ctime()) 14 15 def RecordBlog(title): 16 17 print ("Begin recording the %s! %s" %(title,ctime())) 18 sleep(5) 19 print(‘end recording %s‘%ctime()) 20 21 #創建一個列表,把t1和t2加到列表中去 22 threads = [] 23 t1 = threading.Thread(target=ListenMusic,args=(‘水手‘,)) 24 t2 = threading.Thread(target=RecordBlog,args=(‘python線程‘,)) 25 threads.append(t1) 26 threads.append(t2) 27 28 if __name__ == ‘__main__‘: 29 30 t1.setDaemon(True) #設置t1為守護線程; 註意:一定在start之前設置,否則會報錯 31 for t in threads: 32 33 t.start() 34 35 print ("all over %s" %ctime())
執行結果:
1 Begin listening to 水手. Sat Jan 14 14:02:07 2017 2 Begin recording the python線程! Sat Jan 14 14:02:07 2017 3 all over Sat Jan 14 14:02:07 2017 #設置t1為守護線程,所以會先把這三條先打印出來 4 5 end listening Sat Jan 14 14:02:10 2017 #再等待3秒打印t2, 6 7 end recording Sat Jan 14 14:02:12 2017 #再等待3秒打印這條出來
示例4:設置t2為守護線程,子線程才會跟著主線程一起退出
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 from time import ctime,sleep 7 import time 8 9 def ListenMusic(name): 10 11 print ("Begin listening to %s. %s" %(name,ctime())) 12 sleep(3) 13 print("end listening %s"%ctime()) 14 15 def RecordBlog(title): 16 17 print ("Begin recording the %s! %s" %(title,ctime())) 18 sleep(5) 19 print(‘end recording %s‘%ctime()) 20 21 #創建一個列表,把t1和t2加到列表中去 22 threads = [] 23 t1 = threading.Thread(target=ListenMusic,args=(‘水手‘,)) 24 t2 = threading.Thread(target=RecordBlog,args=(‘python線程‘,)) 25 threads.append(t1) 26 threads.append(t2) 27 28 if __name__ == ‘__main__‘: 29 30 t2.setDaemon(True) # 設置t2為守護線程; 註意:一定在start之前設置,否則會報錯 31 for t in threads: 32 33 t.start() 34 35 print ("all over %s" %ctime())
執行結果:
1 Begin listening to 水手. Sat Jan 14 14:17:09 2017 2 Begin recording the python線程! Sat Jan 14 14:17:09 2017 3 all over Sat Jan 14 14:17:09 2017 #先打印這三條 4 5 end listening Sat Jan 14 14:17:12 2017 #等待3秒,再打印這條;t1結束後,主線程也結束了。
其他方法:
Thread實例對象的方法
# isAlive(): 返回線程是否活動的。 # getName(): 返回線程名。 # setName(): 設置線程名。 threading模塊提供的一些方法: # threading.currentThread(): 返回當前的線程變量。 # threading.enumerate(): 返回一個包含正在運行的線程的list。正在運行指線程啟動後、結束前,不包括啟動前和終止後的線程。 # threading.activeCount(): 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 5 import threading 6 from time import ctime,sleep 7 import time 8 9 def ListenMusic(name): 10 11 print ("Begin listening to %s. %s" %(name,ctime())) 12 sleep(3) 13 print("end listening %s"%ctime()) 14 15 def RecordBlog(title): 16 17 print ("Begin recording the %s! %s" %(title,ctime())) 18 sleep(5) 19 print(‘end recording %s‘%ctime()) 20 21 #創建一個列表,把t1和t2加到列表中去 22 threads = [] 23 t1 = threading.Thread(target=ListenMusic,args=(‘水手‘,)) 24 t2 = threading.Thread(target=RecordBlog,args=(‘python線程‘,)) 25 threads.append(t1) 26 threads.append(t2) 27 28 if __name__ == ‘__main__‘: 29 30 t2.setDaemon(True) # 設置t為守護進程; 註意:一定在start之前設置,否則會報錯 31 for t in threads: 32 t.start() 33 print(t.getName()) #返回線程名稱:Thread-1 34 35 print ("all over %s" %ctime())
GIL(全局解釋器鎖)
無論你啟多少個線程,你有多少個cpu, Python在執行的時候會淡定的在同一時刻只允許一個線程運行。
進程與線程