python自學篇十四[進程:(概念+特徵+單進程+多進程+加鎖+pool+Queue+pipe)+線程:(單線程+僞多線程+守護線程+join阻塞) ]

一.進程

1.進程的概念

  • 計算機的核心是CPU,承擔了所有的計算任務
  • 操作系統是計算機的管理者,負責任務的調度,資源的分配和管理,統領整個計算機硬件
  • 應用程序是具有某種功能的程序,程序是運行於操作系統之上的
  • 進程是一個具有一定獨立功能的程序在一個數據集上的一次動態執行的過程,是操作系統進行資源分配和調度的一個獨立單位,是應用程序運行的載體
  • 進程是一種抽象的概念,從來沒有統一的標準定義
  • 進程一般由程序,數據集合和進程控制塊三部分組成
  • 程序用於描述進程要完成的功能,是控制進程執行的指令集
  • 數據集合是程序在執行時所需要的數據和工作區
  • 程序控制塊包含進程的描述信息和控制信息是進程存在的唯一標誌

2.進程的特徵

  • 獨立性:進程是系統進行資源分配和調度的一個獨立單位
  • 結構性:進程由程序,數據和進程控制塊三部分組成
  • 動態性:進程是程序的一次執行過程,是臨時的,有生命期的,是動態產生,動態消亡的
  • 併發性:任何進程都可以同其他進行一起併發執行

3. 單進程

代碼:

import time
import multiprocessing

def work_1(f,n):#f是修改的文件,n是幾遍
    print('work_1 start')
    for i in range(n):
        with open(f,'a') as fs:#a的方式打開文件
            fs.write('i love pyhton \n')
            time.sleep(1)#睡眠1print('work_1 end')


def work_2(f,n):
    print('work_2 start')
    for i in range(n):
        with open(f,'a') as fs:
            fs.write('come on baby \n')
            time.sleep(1)
    print('work_2 end')

if __name__ == '__main__':
    work_1('file.txt',3)#調用方法
    work_2('file.txt',3)

結果:(在同級目錄下創建file.txt並在裏面寫入內容)

work_1 start
work_1 end
work_2 start
work_2 end

4.多進程

代碼:

import time
import multiprocessing

def work_1(f,n):
    print('work_1 start')
    for i in range(n):
        with open(f,'a') as fs:
            fs.write('i love pyhton \n')
            time.sleep(1)
    print('work_1 end')


def work_2(f,n):
    print('work_2 start')
    for i in range(n):
        with open(f,'a') as fs:
            fs.write('come on baby \n')
            time.sleep(1)
    print('work_2 end')

if __name__ == '__main__':
    p1 = multiprocessing.Process(target=work_1,args = ('file.txt',3))
    p2 = multiprocessing.Process(target=work_2, args=('file.txt', 3))

    p1.start()
    p2.start()

結果:

5.加鎖

代碼:

import time
import multiprocessing

#加鎖
def work_1(f,n,lock):
    print('work_1 start')
    lock.acquire()
    for i in range(n):
        with open(f,'a') as fs:
            fs.write('i love pyhton \n')
            time.sleep(1)
    print('work_1 end')
    lock.release()

def work_2(f,n,lock):
    print('work_2 start')
    lock.acquire()
    for i in range(n):
        with open(f,'a') as fs:
            fs.write('come on baby \n')
            time.sleep(1)
    print('work_2 end')
    lock.release()

if __name__ == '__main__':
    lock=multiprocessing.Lock()
    p1 = multiprocessing.Process(target=work_1,args = ('file.txt',3,lock))
    p2 = multiprocessing.Process(target=work_2, args=('file.txt', 3,lock))

    p1.start()
    p2.start()

結果:

#先寫完進程1再寫進程2
i love pyhton 
i love pyhton 
i love pyhton 
come on baby 
come on baby 
come on baby 

6.pool方法

代碼1:

import os
import multiprocessing
import time

def  work(n):
   print('run work (%s) ,work id %s'%(n,os.getpid()))
   time.sleep(5)
   print('work (%s) stop ,work id %s'%(n,os.getpid()))


if __name__=='__main__':
   print('Parent process %s.' % os.getpid())
   #創建進程池
   p = multiprocessing.Pool(3)
   for i in range(5):
        #創建5個進程,一次進入進程池
        p.apply_async(work, args=(i,))
   p.close()
   p.join()

結果:

Parent process 30656.
run work (0) ,work id 29692
run work (1) ,work id 29304
run work (2) ,work id 29960    #一次只能執行3個進程,首先是012
work (0) stop ,work id 29692   #0執行完畢
run work (3) ,work id 29692    #3加入,此時執行的是123
work (1) stop ,work id 29304   #1執行完畢
run work (4) ,work id 29304    #4加入,此時執行的是123
work (2) stop ,work id 29960
work (3) stop ,work id 29692
work (4) stop ,work id 29304   #234執行完畢

進程已結束,退出代碼 0

代碼2:

import os
import multiprocessing
import time

def music(name,loop):
    print(time.ctime())
    for i in range(loop):
        time.sleep(2)
        print('您現在正在聽的音樂是%s'%name)

def movie(name,loop):
    print(time.ctime())
    for i in range(loop):
        time.sleep(2)
        print('您現在正在看的電影是%s'%name)

if __name__=='__main__':
    pool=multiprocessing.Pool(2)
    pool.apply_async(func=music,args=('花太香',3))
    pool.apply_async(func=movie,args=('王牌特工',4))
    pool.apply_async(func=music, args=('愛的故事上集', 2))
    pool.close()
    # pool.terminate()
    # 比較危險,不要輕易用,直接殺死進程池
    #join阻塞主進程,當子進程執行完畢的時候會繼續往後執行,使用join必須在進程池使用terminate或者close
    pool.join()
    print('結束時間是%s'%time.ctime())

結果:

Fri Jan  3 18:34:32 2020
Fri Jan  3 18:34:32 2020
您現在正在聽的音樂是花太香
您現在正在看的電影是王牌特工
您現在正在聽的音樂是花太香
您現在正在看的電影是王牌特工
您現在正在聽的音樂是花太香
Fri Jan  3 18:34:38 2020
您現在正在看的電影是王牌特工
您現在正在聽的音樂是愛的故事上集
您現在正在看的電影是王牌特工
您現在正在聽的音樂是愛的故事上集
結束時間是Fri Jan  3 18:34:42 2020

進程已結束,退出代碼 0

7.Queue(管道通信)

代碼:

#-*- conding:utf-8 -*-
import multiprocessing
import time
#queue 跨進程通信
def put(q):
   for value in ['A', 'B', 'C']:
       print ('發送 %s 到 queue...' % value)
       q.put(value)  #通過put發送
       time.sleep(2)

## 讀數據進程執行的代碼:
def get(q):
   while True:   #一直循環
       value = q.get(True) #通過get接受隊列中的數據
       print ('從 queue 接受 %s .' % value)

if __name__=='__main__':
   # 父進程創建Queue,並傳給各個子進程:
   q = multiprocessing.Queue()
   pw = multiprocessing.Process(target=put, args=(q,))
   pr = multiprocessing.Process(target=get, args=(q,))
   # 啓動子進程pw,寫入:
   pw.start()
   # 啓動子進程pr,讀取:
   pr.start()
   # 等待pw結束:
   pw.join()
   # pr進程裏是死循環,無法等待其結束,只能強行終止:
   pr.terminate()

結果:

發送 A 到 queue...
從 queue 接受 A .
發送 B 到 queue...
從 queue 接受 B .
發送 C 到 queue...
從 queue 接受 C .

進程已結束,退出代碼 0

8.pipe(實現進程與進程之間通信)

代碼:

#-*- conding:utf-8 -*-
import multiprocessing
import time
#PIPE 管道通信
def put(p):
   for value in ['A', 'B', 'C']:
       print ('發送 %s 到 pipe...' % value)
       p[1].send(value)#發送
       time.sleep(2)

# 讀數據進程執行的代碼:
def get(p):
   while True:
       value = p[0].recv()#接收
       print ('從 pipe 接受 %s .' % value)

if __name__=='__main__':
   # 父進程創建Queue,並傳給各個子進程:
   # p = multiprocessing.Pipe()
   p = multiprocessing.Pipe(duplex=False) #左收右發
   pw = multiprocessing.Process(target=put, args=(p,))
   pr = multiprocessing.Process(target=get, args=(p,))
   # 啓動子進程pw,寫入:
   pw.start()
   # 啓動子進程pr,讀取:
   pr.start()
   # 等待pw結束:
   pw.join()
   # pr進程裏是死循環,無法等待其結束,只能強行終止:
   pr.terminate()

結果:

發送 A 到 pipe...
從 pipe 接受 A .
發送 B 到 pipe...
從 pipe 接受 B .
發送 C 到 pipe...
從 pipe 接受 C .

進程已結束,退出代碼 0

9.生產者消費者模型

代碼:

#-*- conding:utf-8 -*-
import threading
import time
import queue

q = queue.Queue(maxsize=10)
def producer(name):  # 生產者
    count = 1
    while True:
        q.put("辣條%s" % count)
        print("渣女生產一包了辣條", count)
        count += 1
        time.sleep(0.5)


def consumer(name):  # 消費者
    while True:
        print("[%s]取到[%s]並且吃了它..." % (name, q.get()))
        time.sleep(1)


p = threading.Thread(target=producer, args=("丈母孃",))
c1 = threading.Thread(target=consumer, args=("渣男",))
c2 = threading.Thread(target=consumer, args=("老丈人",))

p.start()
c1.start()
c2.start()

結果:

渣女生產一包了辣條 1
[渣男]取到[辣條1]並且吃了它...
渣女生產一包了辣條 [老丈人]取到[辣條2]並且吃了它...2

渣女生產一包了辣條[渣男]取到[辣條3]並且吃了它... 
3
渣女生產一包了辣條[老丈人]取到[辣條4]並且吃了它... 
4
渣女生產一包了辣條[渣男]取到[辣條5]並且吃了它... 
5
渣女生產一包了辣條[老丈人]取到[辣條6]並且吃了它... 
6
渣女生產一包了辣條[渣男]取到[辣條7]並且吃了它... 
7
渣女生產一包了辣條[老丈人]取到[辣條8]並且吃了它... 8

渣女生產一包了辣條[渣男]取到[辣條9]並且吃了它...
 9
........
CTRL+C退出,否則會一直執行

二.線程

1.線程的概念

  • 早期的操作系統中沒有線程的概念,進程是擁有資源和獨立運行的最小單位,也是程序執行的最小單位
  • 任務調度採用的是時間片輪轉的搶佔式調度方式
  • 進程是任務調度的最小單位,每個進程有各自獨立的一塊內存,使得各個進程之間內存地址相互隔離
  • 隨着計算機的發展,對CPU的要求越來越高,進程之間的切換開銷較大,已經無法滿足越來越複雜的程序的要求了。於是就發明了線程,線程是程序執行中一個單一的順序控制流程,是程序執行流的最小單元,是處理器調度和分派的基本單位
  • 一個進程可以有一個或多個線程,各個線程之間共享程序的內存空間(也就是所在進程的內存空間)
  • 一個標準的線程由線程ID,當前指令指針PC,寄存器和堆棧組成。進程由內存空間(代碼,數據,進程空間,打開的文件)和一個或多個線程組成

2.單線程:一件事情一件事情地做

  • 當處理器需要處理多個任務時,必須對這些任務安排執行順序,並按照這個順序來執行任務。假如我們創建了兩個任務:聽音樂(music)和看電影(movie)。在單線程中,我們只能按先後順序來執行這兩個任務
threading.Thread(self, group=None, target=None, name=None, args=(), kwargs={})   

參數group是預留的,用於將來擴展
參數target是一個可調用對象(也稱爲活動[activity]),在線程啓動後執行
參數name是線程的名字。默認值爲“Thread-N“,N是一個數字
參數args和kwargs分別表示調用target時的參數列表和關鍵字參數

  • 代碼:
import time
import threading

def music(name,loop):
    for i in range(loop):
        print('listen music %s %s'%(name,time.ctime()))
        time.sleep(1)

def movie(name,loop):
    for i in range(loop):
        print('look   movie %s %s'%(name,time.ctime()))
        time.sleep(1)

if __name__ == '__main__':
    music('愛的故事上集',3)
    movie('曉生克的救贖',4)
    print('end time %s'%time.ctime())

結果:

listen music 愛的故事上集 Fri Jan  3 17:50:56 2020
listen music 愛的故事上集 Fri Jan  3 17:50:57 2020
listen music 愛的故事上集 Fri Jan  3 17:50:58 2020
look   movie 曉生克的救贖 Fri Jan  3 17:50:59 2020
look   movie 曉生克的救贖 Fri Jan  3 17:51:00 2020
look   movie 曉生克的救贖 Fri Jan  3 17:51:01 2020
look   movie 曉生克的救贖 Fri Jan  3 17:51:02 2020
end time Fri Jan  3 17:51:03 2020
進程已結束,退出代碼 0

3.多線程(python中的多線程是僞多線程):同時做一件或多件事

代碼:

import time
import threading

def music(name,loop):
    for i in range(loop):
        print('listen music %s %s %s'%(name,time.ctime(),threading.Thread.getName(t1)))#輸出線程名字
        time.sleep(1)

def movie(name,loop):
    for i in range(loop):
        print('look movie %s %s %s'%(name,time.ctime(),threading.Thread.getName(t2)))
        time.sleep(1)

#創建多線程
t1 = threading.Thread(target= music,args=('愛的故事上集',4))
t2 = threading.Thread(target= movie,args=('肖生克的救贖',4),name = 'movieThread')#設置線程名字
t1.setName('musicThread')#設置線程名字

if __name__ == '__main__':
    # 啓動線程
    t1.start()
    t2.start()
    print('end time %s'%time.ctime())

4.守護主線程:

代碼:

#守護主線程,主線程結束殺死子線程
t1.setDaemon(True)
t2.setDaemon(True)

查看線程標識,ID

代碼:

print(t1.ident)
print(t2.ident)

join 可以對主線程進行阻塞,等所有的子線程運行結束在運行主線程

代碼:

t1.join() 
t2.join()

加鎖

代碼:

import time
import threading

balance = 0#定義一個變量

def change(n):
    global balance
    balance+=n
    balance-=n

lock = threading.Lock()  #獲取線程鎖
def run_thread(n):
    for i in range(1000000):
        lock.acquire() #獲取鎖
        try:
            change(n)
        finally:
            lock.release()#釋放鎖
t1 = threading.Thread(target= run_thread,args=(4,))#創建線程
t2 = threading.Thread(target= run_thread,args=(8,))

t1.start()
t2.start()# 啓動線程
t1.join()#對主線程進行阻塞
t2.join()
print(balance)

三.進程與線程的區別

  • 線程是程序執行的最小單位,而進程是操作系統分配資源的最小單位

  • 一個進程由一個或多個線程組成,線程是一個進程中代碼的不同執行路線

  • 進程之間相互獨立,但同一進程下的各個線程之間共享程序的內存空間(包括代碼段,數據集,堆等)及一些進程級的資源(如打開文件和信號等),某進程內的線程在其他進程不可見

  • 調度和切換:線程上下文切換比進程上下文切換要快得多

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章