例子簡單瞭解線程與進程

目錄

線程與進程概念

進程

線程

線程與進程狀態

協程

總體

線程例

基本操作

全局變量操作

進程例


線程與進程概念

進程

進程(Process)是計算機中的程序關於某數據集合上的一次運行活動。是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。在早期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代面向線程設計的計算機結構中。

線程

線程(Thread)是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流。

線程與進程狀態

進程退出時該進程所產生的線程都會被強制退出並清除線程可與屬於同一進程的其它線程共享進程所擁有的全部資源
但是其本身基本上不擁有系統資源,只擁有一點在運行中必不可少的信息(如程序計數器、一組寄存器和棧)。


多進程適合在CPU 密集型操作(cpu 操作指令比較多,如科學計算,位數多的浮點運算)
多線程適合在IO 密集型操作(讀寫數據操作較多的,比如爬蟲)
線程是併發進程是並行進程之間相互獨立,是系統分配資源的最小單位,同一個進程中的所有線程共享資源。

協程

協程是用戶態的輕量級線程,調度有用戶控制,擁有自己的寄存器上下文和棧,切換基本沒有內核切換的開銷,切換靈活。

總體

  1. 一個進程中可以併發多個線程,每條線程並行執行不同的任務。
  2. 進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。
  3. 線程是屬於進程的,線程運行在進程空間內,同一進程所產生的線程共享同一內存空間。
  4. 線程是併發,進程是並行。

線程例

基本操作

#線程基本操作
import threading
import time
def cxk(n):
    print('運行線程:',n)

for i in range(10):# 創建10個線程
    t = threading.Thread(target=cxk, args=(i,))    # 線程運行的函數和參數
    t.setDaemon(True) # 設置爲守護線程(在主線程線程結束後自動退出,默認爲False即主線程線程結束後子線程仍在執行)
    t.start() # 啓動線程

輸出:
運行線程: 0
運行線程: 1
運行線程: 2
運行線程: 3
運行線程: 4
運行線程: 5
運行線程: 6
運行線程: 7
運行線程: 8
運行線程: 9

全局變量操作

import threading,time
def cxk(n):
    global j
    j+=1
    time.sleep(1)
    print('運行線程:%s,變量j的情況:%s'%(n,j))
j=-1
for i in range(10):# 創建10個線程
    t = threading.Thread(target=cxk, args=(i,))    # 線程運行的函數和參數
    t.setDaemon(True) # 設置爲守護線程(在主線程線程結束後自動退出,默認爲False即主線程線程結束後子線程仍在執行)
    t.start() # 啓動線程

如果處理速度比較快並不會出現髒數據的情況
>>>
運行線程:0,變量j的情況:0
運行線程:1,變量j的情況:1
運行線程:2,變量j的情況:2
運行線程:3,變量j的情況:3
運行線程:4,變量j的情況:4
運行線程:5,變量j的情況:5
運行線程:6,變量j的情況:6
運行線程:7,變量j的情況:7
運行線程:8,變量j的情況:8
運行線程:9,變量j的情況:9

但是當我們每個進程睡眠加個進去,time.sleep(1),相當於處

理速度比較慢的時候,就會變成下面這樣,因爲操作的全部線程執行完後第一個線程打印部分還在睡眠,當他打印j變量的時候全部線程已經執行完畢了
>>>
運行線程:0,變量j的情況:9
運行線程:1,變量j的情況:9
運行線程:3,變量j的情況:9
運行線程:5,變量j的情況:9
運行線程:4,變量j的情況:9
運行線程:8,變量j的情況:9
運行線程:7,變量j的情況:9
運行線程:2,變量j的情況:9
運行線程:9,變量j的情況:9
運行線程:6,變量j的情況:9

解決辦法就是加鎖

# 線程鎖
import threading,time
def cxk(n):
    lock.acquire()      # 開始鎖
    global j
    j+=1
    time.sleep(1)
    print('運行線程:%s,變量j的情況:%s'%(n,j))
    lock.release()      # 結束鎖
j=-1
lock = threading.RLock()    # 定義線程鎖
for i in range(10):# 創建10個線程
    t = threading.Thread(target=cxk, args=(i,))    # 線程運行的函數和參數
    t.setDaemon(True) # 設置爲守護線程(在主線程線程結束後自動退出,默認爲False即主線程線程結束後子線程仍在執行)
    t.start() # 啓動線程


#輸出
>>>
運行線程:0,變量j的情況:0
運行線程:1,變量j的情況:1
運行線程:2,變量j的情況:2
運行線程:3,變量j的情況:3
運行線程:4,變量j的情況:4
運行線程:5,變量j的情況:5
運行線程:6,變量j的情況:6
運行線程:7,變量j的情況:7
運行線程:8,變量j的情況:8
運行線程:9,變量j的情況:9

那麼多線程處理文件的時候會出現文件資源出現問題的情況嗎?我們來爲每個線程同時向同一個文件寫十句話。

import threading,time
def cxk(n):
    with open('cxk.txt','a+') as f:
        for i in range(0,10):
            time.sleep(1)
            f.write('我是線程:%s \n'%str(n))
    print('線程:%s 寫入成功'%str(n))
for i in range(10):# 創建10個線程
    t = threading.Thread(target=cxk, args=(i,))    # 線程運行的函數和參數
    t.setDaemon(True) # 設置爲守護線程(在主線程線程結束後自動退出,默認爲False即主線程線程結束後子線程仍在執行)
    t.start() # 啓動線程

由圖可以看出沒什麼問題,並沒出現同一文件不能處理,我們加大處理速度試試,睡眠 。

也沒什麼問題,就是線程完成速度不一樣,並沒出現第一個線程寫完第一句第二個線程接着寫第二句,但是這樣看起來不像是並行,倒像是串行的。。。我就在想會不會是在並行的情況下,第一個線程睡眠時第二個線程也是同時處於睡眠狀態,所以寫入也是按順序的。。。不過我在網上得到下面這一段話:
"""
在Python的原始解釋器CPython中存在着GIL,因此在解釋執行Python代碼時,會產生互斥鎖來限制線程對共享資源的訪問,直到解釋器遇到I/O操作或者操作次數達到一定數目時纔會釋放GIL,所以有GIL效果就是:** 一個進程內同一時間只能允許一個線程進行運算 ** (這尼瑪不就是單線程嗎?)

python的多線程只能在一個核心上跑(創始人沒想到會有多核出現),就是單核的上下文切換,所以很雞肋。
於是協程在python大展拳腳,好多框架都是使用協程來解決多任務的,而不是線程(scrapy,tornado)。

"""
最後似懂非懂,也就是說到底python的多線程就不是真正的並行。。。

不過python的多線程確實能提升效率,並且使用tkinter時打開不同窗口使用多線程不會產生卡住狀態,這篇博客也採用多線程處理,效率大大提升,還有以前的tkinter練習也基本用到了,有興趣可以去看看。

進程例

進程我用的不多,因爲我用notebook運行多進程時只有主進程會顯示,子進程調用的函數沒反應,只能打包成py文件去cmd下運行。

#寫入該句話,運行時直接生成py文件
%%writefile cxkkxc.py
import multiprocessing,time
"""
進程各自持有一份數據,默認無法共享數據
當創建進程時(非使用時),共享數據會被拿到子進程中,當進程中執行完畢後,再賦值給原值。
"""
def cxk(n):
    with open('cxk2.txt','a+') as f:
        for i in range(0,10):
            f.write('我是進程:%s \n'%str(n))
            time.sleep(1)
    print('進程:%s 寫入成功'%str(n))
    
if __name__ == "__main__":
    for i in range(1,3):
        p = multiprocessing.Process(target = cxk, args = (i,))
        p.start()
        print("p.pid:", p.pid)
        print ("p.name:", p.name)
        print ("p.is_alive:", p.is_alive())

這裏我試用的也是打開文件的形式,只不過是以with open打開的,加了睡眠沒有加鎖也沒出現資源共享問題,搞不懂搞不懂,可能with open 會自動關閉文件吧,每寫完一句關閉第二個進程再打開寫入。以後再探究探究。最近可能沒空咯,參加了一個比賽,等忙完這陣再繼續更。

 

 

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