python進程、線程的學習心得

什麼是多線程競爭?html

線程不是獨立的,同一個進程裏的線程,線程間的數據是共享的,多線程操做時,容易形成數據的混亂,線程不安全。python

如何解決?程序員

互斥鎖。算法

好處:可以保證某段關鍵代碼執行時,只有一個線程操做,保證原子性,避免多線程下的資源競爭。安全

壞處:性能降低,阻止了多線程的併發執行。致命問題,有可能產生死鎖。多線程

解釋一下什麼是鎖,有哪幾種鎖?併發

鎖是python提供的對線程控制的對象。互斥鎖,可重入鎖,死鎖。app

互斥鎖:同一時刻只容許一個線程操做,具備排他性和惟一性。好比A、B兩個線程,A操做時,B只能等着,A執行完,B才能操做。dom

可重入鎖:有時候在同一個線程中,咱們可能會屢次請求同一資源(就是,獲取同一鎖鑰匙),俗稱鎖嵌套。異步

死鎖:互相干等着,都不釋放鎖,程序沒法執行下去。

GIL鎖(全局解釋器鎖):限制多線程的同時執行,同一時間,只有一個線程執行,因此cpython裏的多線程實際上是僞多線程。python使用協程代替多線程來解決,更輕量級的線程,進程和線程的切換時系統肯定的,而協程的切換是由程序員肯定的,而模塊gevent下切換是遇到耗時操做纔會切換的。進程有線程,線程有協程。

什麼是線程安全,什麼是互斥鎖?

做用:保證同一時刻只有一個線程訪問一個對象的功能。

因爲同一進程的多個線程之間是共享系統資源的,多個線程同時對一個對象進行操做時,一個線程對其進行操做還沒有結束cpu時間片切換到另外一個線程對其操做,再切換回來時,數據已被修改,致使結果出現錯誤。此時須要對被操做的對象添加互斥鎖,保證每一個線程對該對象的操做都能獲得正確的結果。

說說下面幾個概念:同步,異步,阻塞,非阻塞?

同步:排隊,一一執行,一個執行完,才執行下一個。

異步:沒有前後順序,同時執行。

阻塞:程序執行到某段,不往下執行了,卡在那裏了。

非阻塞:若是這段卡主了,會執行其餘代碼。

什麼是殭屍進程和孤兒進程?怎麼避免殭屍進程?

孤兒進程:父進程退出,子進程還在運行的這些子進程都是孤兒進程,孤兒進程將被init 進程(進
程號爲1)所收養,並由init 進程對它們完成狀態收集工做。
殭屍進程:在UNIX 系統中,一個進程結束了,可是他的父進程沒有等待(調用wait / waitpid)他, 那麼他將變成一個殭屍進程

避免殭屍進程的方法:
1.fork 兩次用孫子進程去完成子進程的任務;
2.用wait()函數使父進程阻塞;
3.使用信號量,在signal handler 中調用waitpid,這樣父進程不用阻塞。

 

常見問題總結:

1. 線程和進程有什麼不一樣?
    ```python
    進程:1>系統進行資源分配和調度的一個獨立單元
          2>進程間不共享全局變量,須要進行進程間的通訊
          3>進程在運行過程當中爲獨立的內存單元
    線程:1>進程的一個實體,是CPU調度和分派的基本單位
          2>同時對一個全局變量進行修改,容易混亂(不必定執行完就換線程)
          3>線程依賴進程的存在,線程併發性高,佔用資源比進程少
          4>多線程共享非全局變量不用加鎖
          5>多線程到同一個函數裏執行,函數裏的變量各是各的
    ```
2. 什麼是單任務、多任務程序?
    ```python
    參考:
    單任務是指一次只能運行一個程序,不能同時運行多個程序
    多任務是指能夠同時運行多個程序
    ```
3. Linux系統是\_\_\_\_任務\_\_\_\_用戶的系統?
    ```python
    Linux系統是多任務多用戶的系統
    ```
4. 以單核cpu爲例,它是怎樣完成多任務的?
    ```python
    輪流切換執行
    微觀上,在任何一個時刻只有一個程序被執行
    但切換速度很是的快,所以在宏觀上,看上去多個任務在一塊兒執行同樣
    ```
5. 怎樣區分並行和併發?
    ```python
    簡單來說:
    並行是指多個cpu同時執行多個任務
    併發是指單個cpu輪流切換執行多個任務
    ```
6. 程序和進程有什麼區別?
    ```python
    簡而言之,代碼沒有被運行以前是一個程序,當運行起來後就能成爲進程
    ```
8. 子進程和父進程是什麼?
    ```python
    經過進程a產生的進程b,a進程就是父進程,b就是子進程
    ```
9. getpid、getppid的做用是什麼?
    ```python
    getpid    獲取當前進程的進程號
    getppid    獲取當前進程的父進程的進程號
    ```
10. 建立出來的多個子進程,同時對一個相同名字的全局變量操做時會出錯麼?爲何?
    ```python
    不會出錯
    由於進程之間的資源是不共享的,各自擁有各自的一份該變量,操做互不影響
    ```

12. 建立出來的子進程和父進程究竟是誰先執行?爲何?
    ```python
    不肯定
    由於多任務中,誰先被執行,是由cpu的調度算法來決定的,cpu會保證每一個進程都能被平均的執行一段時間,一次你看上去會是隨機的
    ```

14. multiprocessing模塊的目的是什麼?
    ```python
    使用multiprocessing模塊中的Process建立一個子進程
    ```
15. 怎樣用multiprocessing模塊中的Process建立一個子進程?請寫出基本代碼
   

 

from multiprocessing import Process
    def mission():
        for i in range(5):
            print(i)
    if __name__ == "__main__":
        p = Process(target=mission)    # 建立進程實例
        p.start()    # 啓動子進程
        p.join()    # 讓父進程等待

16. multiprocessing模塊中的Process建立了一個子進程後,怎樣讓子進程開始執行?
    ```python
    調用start方法
    ```

18. 若是一個程序須要同時執行多個任務,那麼通常會怎麼作?
    ```python
    使用多進程或者多線程來實現
    ```

20. 什麼是進程池?有什麼用?
    ```python
    進程池就是建立出必定固定數量的進程,去執行多個任務
    節約建立進程和銷燬進程所消耗的資源和空間
    當某個任務被執行完畢後,利用該進程再去執行其餘的任務,大大提升效率
    ```

19. 爲了完成多個任務一塊兒執行,能夠建立多個子進程來執行任務,那麼爲何還要進程池呢?
    ```python
    由於每建立一個進程都會申請內存空間,消耗資源,進程結束又要回收資源
    若是反覆建立進程,又結束進程,會嚴重影響性能
    進程池的目的就是複用進程,大大提升程序的運行效率
    ```

21. 什麼是進程間通訊?
    ```python
    簡而言之
    進程間的資源是不共享的,所以若是在不一樣進程間的任務須要相互使用對方的資源或信息
    那麼就須要在進程之間傳遞信息、傳遞資源,這就是進程間通訊
    ```

22. 爲何須要進程間通訊?
    ```python
    同上
    ```

23. multiprocessing模塊中Queue怎樣發送、取出數據?
    ```python
    q = Queue()
    q.put(數據)  # 存放數據
    q.get()  # 取出數據
    ```

# 關卡二

練習題:1. 使用Process建立1個子進程,讓子進程每1秒鐘打印1個數字,數字從1開始一直到10,即1.2.3......10
    

 

    # coding=utf-8
    import time
    from multiprocessing import Process
    # 定義子進程的須要執行的任務 函數
    def mission():
        #打印1-10
        for i in range(1,11):
            print(i)
            time.sleep(1)

    def main():
        p = Process(target=mission)
        p.start()
        p.join()
    if __name__ == "__main__":
        main() 


2. 使用multiprocessing模塊中的Queue,完成子進程中將hello傳遞到父進程中,父進程打印出來

 

    # coding=utf-8
    import time
    from multiprocessing import Process, Queue
    # 定義父進程的須要執行的任務 函數
    def parent_mission(que):
        data = que.get()    # 從隊列獲取數據打印
        print(data)
        time.sleep(5)

    # 定義子進程的須要執行的任務 函數   
    def children_mission(que):
        data = "hello"   # 輸入hello就會被父進程拿到
        que.put(data)    #  往隊列添加數據
        time.sleep(3)

    def main():
        q = Queue()    # 在父進程中定義隊列,實現與子進程通訊
        p = Process(target=children_mission, args=(q,))
        p.start()    # 啓動子進程 執行任務
        parent_mission(q)    # 在父進程中 執行任務
        p.join()
    if __name__ == "__main__":
        main()    

1. 使用進程池完成以下要求:
    * 將/usr/lib/python3.5文件夾下的全部py結尾的文件copy到 桌面上的Test文件夾中
    * 用多任務(多進程或者多線程)的方式完成Test文件夾中的全部內容複製
    * 新的文件夾的名字爲「Test-附件」
    * 在複製文件的過程當中,實時顯示覆制的進度

 

import multiprocessing
import os
import time
import random


def copy_file(queue, file_name,source_folder_name, dest_folder_name):
    """copy文件到指定的路徑"""
    f_read = open(source_folder_name + "/" + file_name, "rb")
    f_write = open(dest_folder_name + "/" + file_name, "wb")
    while True:
        time.sleep(random.random())
        content = f_read.read(1024)
        if content:
            f_write.write(content)
        else:
            break
    f_read.close()
    f_write.close()

    # 發送已經拷貝完畢的文件名字
    queue.put(file_name)


def main():
    # 獲取要複製的文件夾
    source_folder_name = input("請輸入要複製文件夾名字:")

    # 整理目標文件夾
    dest_folder_name = source_folder_name + "[副本]"

    # 建立目標文件夾
    try:
        os.mkdir(dest_folder_name)
    except:
        pass  # 若是文件夾已經存在,那麼建立會失敗

    # 獲取這個文件夾中全部的普通文件名
    file_names = os.listdir(source_folder_name)

    # 建立Queue
    queue = multiprocessing.Manager().Queue()

    # 建立進程池
    pool = multiprocessing.Pool(3)

    for file_name in file_names:
        # 向進程池中添加任務
        pool.apply_async(copy_file, args=(queue, file_name, source_folder_name, dest_folder_name))

    # 主進程顯示進度
    pool.close()

    all_file_num = len(file_names)
    while True:
        file_name = queue.get()
        if file_name in file_names:
            file_names.remove(file_name)

        copy_rate = (all_file_num-len(file_names))*100/all_file_num
        print("\r%.2f...(%s)" % (copy_rate, file_name) + " "*50, end="")
        if copy_rate >= 100:
            break
    print()


if __name__ == "__main__":
    main()

 

 

 

 

什麼是多線程競爭?

線程不是獨立的,同一個進程裏的線程,線程間的數據是共享的,多線程操做時,容易形成數據的混亂,線程不安全。

如何解決?

互斥鎖。

好處:可以保證某段關鍵代碼執行時,只有一個線程操做,保證原子性,避免多線程下的資源競爭。

壞處:性能降低,阻止了多線程的併發執行。致命問題,有可能產生死鎖。

解釋一下什麼是鎖,有哪幾種鎖?

鎖是python提供的對線程控制的對象。互斥鎖,可重入鎖,死鎖。

互斥鎖:同一時刻只容許一個線程操做,具備排他性和惟一性。好比A、B兩個線程,A操做時,B只能等着,A執行完,B才能操做。

可重入鎖:有時候在同一個線程中,咱們可能會屢次請求同一資源(就是,獲取同一鎖鑰匙),俗稱鎖嵌套。

死鎖:互相干等着,都不釋放鎖,程序沒法執行下去。

GIL鎖(全局解釋器鎖):限制多線程的同時執行,同一時間,只有一個線程執行,因此cpython裏的多線程實際上是僞多線程。python使用協程代替多線程來解決,更輕量級的線程,進程和線程的切換時系統肯定的,而協程的切換是由程序員肯定的,而模塊gevent下切換是遇到耗時操做纔會切換的。進程有線程,線程有協程。

什麼是線程安全,什麼是互斥鎖?

做用:保證同一時刻只有一個線程訪問一個對象的功能。

因爲同一進程的多個線程之間是共享系統資源的,多個線程同時對一個對象進行操做時,一個線程對其進行操做還沒有結束cpu時間片切換到另外一個線程對其操做,再切換回來時,數據已被修改,致使結果出現錯誤。此時須要對被操做的對象添加互斥鎖,保證每一個線程對該對象的操做都能獲得正確的結果。

說說下面幾個概念:同步,異步,阻塞,非阻塞?

同步:排隊,一一執行,一個執行完,才執行下一個。

異步:沒有前後順序,同時執行。

阻塞:程序執行到某段,不往下執行了,卡在那裏了。

非阻塞:若是這段卡主了,會執行其餘代碼。

什麼是殭屍進程和孤兒進程?怎麼避免殭屍進程?

孤兒進程:父進程退出,子進程還在運行的這些子進程都是孤兒進程,孤兒進程將被init 進程(進
程號爲1)所收養,並由init 進程對它們完成狀態收集工做。
殭屍進程:在UNIX 系統中,一個進程結束了,可是他的父進程沒有等待(調用wait / waitpid)他, 那麼他將變成一個殭屍進程

避免殭屍進程的方法:
1.fork 兩次用孫子進程去完成子進程的任務;
2.用wait()函數使父進程阻塞;
3.使用信號量,在signal handler 中調用waitpid,這樣父進程不用阻塞。

 

常見問題總結:

1. 線程和進程有什麼不一樣?
    ```python
    進程:1>系統進行資源分配和調度的一個獨立單元
          2>進程間不共享全局變量,須要進行進程間的通訊
          3>進程在運行過程當中爲獨立的內存單元
    線程:1>進程的一個實體,是CPU調度和分派的基本單位
          2>同時對一個全局變量進行修改,容易混亂(不必定執行完就換線程)
          3>線程依賴進程的存在,線程併發性高,佔用資源比進程少
          4>多線程共享非全局變量不用加鎖
          5>多線程到同一個函數裏執行,函數裏的變量各是各的
    ```
2. 什麼是單任務、多任務程序?
    ```python
    參考:
    單任務是指一次只能運行一個程序,不能同時運行多個程序
    多任務是指能夠同時運行多個程序
    ```
3. Linux系統是\_\_\_\_任務\_\_\_\_用戶的系統?
    ```python
    Linux系統是多任務多用戶的系統
    ```
4. 以單核cpu爲例,它是怎樣完成多任務的?
    ```python
    輪流切換執行
    微觀上,在任何一個時刻只有一個程序被執行
    但切換速度很是的快,所以在宏觀上,看上去多個任務在一塊兒執行同樣
    ```
5. 怎樣區分並行和併發?
    ```python
    簡單來說:
    並行是指多個cpu同時執行多個任務
    併發是指單個cpu輪流切換執行多個任務
    ```
6. 程序和進程有什麼區別?
    ```python
    簡而言之,代碼沒有被運行以前是一個程序,當運行起來後就能成爲進程
    ```
8. 子進程和父進程是什麼?
    ```python
    經過進程a產生的進程b,a進程就是父進程,b就是子進程
    ```
9. getpid、getppid的做用是什麼?
    ```python
    getpid    獲取當前進程的進程號
    getppid    獲取當前進程的父進程的進程號
    ```
10. 建立出來的多個子進程,同時對一個相同名字的全局變量操做時會出錯麼?爲何?
    ```python
    不會出錯
    由於進程之間的資源是不共享的,各自擁有各自的一份該變量,操做互不影響
    ```

12. 建立出來的子進程和父進程究竟是誰先執行?爲何?
    ```python
    不肯定
    由於多任務中,誰先被執行,是由cpu的調度算法來決定的,cpu會保證每一個進程都能被平均的執行一段時間,一次你看上去會是隨機的
    ```

14. multiprocessing模塊的目的是什麼?
    ```python
    使用multiprocessing模塊中的Process建立一個子進程
    ```
15. 怎樣用multiprocessing模塊中的Process建立一個子進程?請寫出基本代碼
   

  1.  
    from multiprocessing import Process
  2.  
    def mission():
  3.  
            for i in range( 5):
  4.  
                print(i)
  5.  
    if __name__ == "__main__":
  6.  
            p = Process(target=mission)     # 建立進程實例
  7.  
            p.start()     # 啓動子進程
  8.  
            p.join()     # 讓父進程等待

16. multiprocessing模塊中的Process建立了一個子進程後,怎樣讓子進程開始執行?
    ```python
    調用start方法
    ```

18. 若是一個程序須要同時執行多個任務,那麼通常會怎麼作?
    ```python
    使用多進程或者多線程來實現
    ```

20. 什麼是進程池?有什麼用?
    ```python
    進程池就是建立出必定固定數量的進程,去執行多個任務
    節約建立進程和銷燬進程所消耗的資源和空間
    當某個任務被執行完畢後,利用該進程再去執行其餘的任務,大大提升效率
    ```

19. 爲了完成多個任務一塊兒執行,能夠建立多個子進程來執行任務,那麼爲何還要進程池呢?
    ```python
    由於每建立一個進程都會申請內存空間,消耗資源,進程結束又要回收資源
    若是反覆建立進程,又結束進程,會嚴重影響性能
    進程池的目的就是複用進程,大大提升程序的運行效率
    ```

21. 什麼是進程間通訊?
    ```python
    簡而言之
    進程間的資源是不共享的,所以若是在不一樣進程間的任務須要相互使用對方的資源或信息
    那麼就須要在進程之間傳遞信息、傳遞資源,這就是進程間通訊
    ```

22. 爲何須要進程間通訊?
    ```python
    同上
    ```

23. multiprocessing模塊中Queue怎樣發送、取出數據?
    ```python
    q = Queue()
    q.put(數據)  # 存放數據
    q.get()  # 取出數據
    ```

# 關卡二

練習題:1. 使用Process建立1個子進程,讓子進程每1秒鐘打印1個數字,數字從1開始一直到10,即1.2.3......10
    

  1.  
        # coding=utf-8
  2.  
        import time
  3.  
        from multiprocessing import Process
  4.  
        # 定義子進程的須要執行的任務 函數
  5.  
        def mission():
  6.  
            #打印1-10
  7.  
            for i in range( 1, 11):
  8.  
                print(i)
  9.  
                time.sleep( 1)
  10.  
     
  11.  
        def main():
  12.  
            p = Process(target=mission)
  13.  
            p.start()
  14.  
            p.join()
  15.  
        if __name__ == "__main__":
  16.  
            main() 


2. 使用multiprocessing模塊中的Queue,完成子進程中將hello傳遞到父進程中,父進程打印出來
 

  1.  
      # coding=utf-8
  2.  
        import time
  3.  
        from multiprocessing import Process, Queue
  4.  
        # 定義父進程的須要執行的任務 函數
  5.  
        def parent_mission(que):
  6.  
            data = que.get()     # 從隊列獲取數據打印
  7.  
            print(data)
  8.  
            time.sleep( 5)
  9.  
     
  10.  
        # 定義子進程的須要執行的任務 函數   
  11.  
        def children_mission(que):
  12.  
            data = "hello"   # 輸入hello就會被父進程拿到
  13.  
            que.put(data)     #  往隊列添加數據
  14.  
            time.sleep( 3)
  15.  
     
  16.  
        def main():
  17.  
            q = Queue()     # 在父進程中定義隊列,實現與子進程通訊
  18.  
            p = Process(target=children_mission, args=(q,))
  19.  
            p.start()     # 啓動子進程 執行任務
  20.  
            parent_mission(q)     # 在父進程中 執行任務
  21.  
            p.join()
  22.  
        if __name__ == "__main__":
  23.  
            main()    

1. 使用進程池完成以下要求:
    * 將/usr/lib/python3.5文件夾下的全部py結尾的文件copy到 桌面上的Test文件夾中
    * 用多任務(多進程或者多線程)的方式完成Test文件夾中的全部內容複製
    * 新的文件夾的名字爲「Test-附件」
    * 在複製文件的過程當中,實時顯示覆制的進度

  

import multiprocessing
import os
import time
import random


def copy_file(queue, file_name,source_folder_name,  dest_folder_name):
    """copy文件到指定的路徑"""
    f_read = open(source_folder_name + "/" + file_name, "rb")
    f_write = open(dest_folder_name + "/" + file_name, "wb")
    while True:
        time.sleep(random.random())
        content = f_read.read(1024)
        if content:
            f_write.write(content)
        else:
            break
    f_read.close()
    f_write.close()

    # 發送已經拷貝完畢的文件名字
    queue.put(file_name)


def main():
    # 獲取要複製的文件夾
    source_folder_name = input("請輸入要複製文件夾名字:")

    # 整理目標文件夾
    dest_folder_name = source_folder_name + "[副本]"

    # 建立目標文件夾
    try:
        os.mkdir(dest_folder_name)
    except:
        pass  # 若是文件夾已經存在,那麼建立會失敗

    # 獲取這個文件夾中全部的普通文件名
    file_names = os.listdir(source_folder_name)

    # 建立Queue
    queue = multiprocessing.Manager().Queue()

    # 建立進程池
    pool = multiprocessing.Pool(3)

    for file_name in file_names:
        # 向進程池中添加任務
        pool.apply_async(copy_file, args=(queue, file_name, source_folder_name, dest_folder_name))

    # 主進程顯示進度
    pool.close()

    all_file_num = len(file_names)
    while True:
        file_name = queue.get()
        if file_name in file_names:
            file_names.remove(file_name)

        copy_rate = (all_file_num-len(file_names))*100/all_file_num
        print("\r%.2f...(%s)" % (copy_rate, file_name) + " "*50, end="")
        if copy_rate >= 100:
            break
    print()


if __name__ == "__main__":
    main()

 

 

 

  1.  1 import multiprocessing
     2 import os
     3 import time
     4 import random
     5 
     6 
     7 def copy_file(queue, file_name,source_folder_name,  dest_folder_name):
     8     """copy文件到指定的路徑"""
     9     f_read = open(source_folder_name + "/" + file_name, "rb")
    10     f_write = open(dest_folder_name + "/" + file_name, "wb")
    11     while True:
    12         time.sleep(random.random())
    13         content = f_read.read(1024)
    14         if content:
    15             f_write.write(content)
    16         else:
    17             break
    18     f_read.close()
    19     f_write.close()
    20 
    21     # 發送已經拷貝完畢的文件名字
    22     queue.put(file_name)
    23 
    24 
    25 def main():
    26     # 獲取要複製的文件夾
    27     source_folder_name = input("請輸入要複製文件夾名字:")
    28 
    29     # 整理目標文件夾
    30     dest_folder_name = source_folder_name + "[副本]"
    31 
    32     # 建立目標文件夾
    33     try:
    34         os.mkdir(dest_folder_name)
    35     except:
    36         pass  # 若是文件夾已經存在,那麼建立會失敗
    37 
    38     # 獲取這個文件夾中全部的普通文件名
    39     file_names = os.listdir(source_folder_name)
    40 
    41     # 建立Queue
    42     queue = multiprocessing.Manager().Queue()
    43 
    44     # 建立進程池
    45     pool = multiprocessing.Pool(3)
    46 
    47     for file_name in file_names:
    48         # 向進程池中添加任務
    49         pool.apply_async(copy_file, args=(queue, file_name, source_folder_name, dest_folder_name))
    50 
    51     # 主進程顯示進度
    52     pool.close()
    53 
    54     all_file_num = len(file_names)
    55     while True:
    56         file_name = queue.get()
    57         if file_name in file_names:
    58             file_names.remove(file_name)
    59 
    60         copy_rate = (all_file_num-len(file_names))*100/all_file_num
    61         print("\r%.2f...(%s)" % (copy_rate, file_name) + " "*50, end="")
    62         if copy_rate >= 100:
    63             break
    64     print()
    65 
    66 
    67 if __name__ == "__main__":
    68     main()
     uma 
相關文章
相關標籤/搜索