国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

python綜合學習一之多線程

cjie / 813人閱讀

摘要:如下面的例子,在學習線程時,將文件名命名為腳本完全正常沒問題,結果報下面的錯誤。最大的問題就是的多線程程序并不能利用多核的優勢比如一個使用了多個線程的計算密集型程序只會在一個單上面運行。

本文記錄學習Python遇到的問題和一些常用用法,注本開發環境的Python版本為2.7。
一、python文件命名

在python文件命名時,一定要注意不能和系統默認的模塊名沖突,否則會報錯。
如下面的例子,在學習線程時,將文件名命名為 threading.py,Python腳本完全正常沒問題,結果報下面的錯誤:AttributeError: "module" object has no attribute "xxx"

threading.py

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_test.py
@time: 18/8/25 09:14
"""

import threading

# 獲取已激活的線程數
print(threading.active_count())

執行:

?  baseLearn python threading/threading.py
Traceback (most recent call last):
  File "threading/threading.py", line 9, in 
    import threading
  File "/Users/kaiyiwang/Code/python/baseLearn/threading/threading.py", line 12, in 
    print(threading.active_count())
AttributeError: "module" object has no attribute "active_count"
?  baseLearn
問題定位:

查看import庫的源文件,發現源文件存在且沒有錯誤,同時存在源文件的.pyc文件

問題解決:

1.命名py腳本時,不要與python預留字,模塊名等相同

2.刪除該庫的.pyc文件(因為py腳本每次運行時均會生成.pyc文件;在已經生成.pyc文件的情況下,若代碼不更新,運行時依舊會走pyc,所以要刪除.pyc文件),重新運行代碼;或者找一個可以運行代碼的環境,拷貝替換當前機器的.pyc文件即可

將腳本文件名重新命名為threading_test.py,然后執行,就不會報錯了。

?  baseLearn python threading/threading_test.py
1
?  baseLearn
二、多線程threading

多線程是加速程序計算的有效方式,Python的多線程模塊threading上手快速簡單,從這節開始我們就教大家如何使用它。

1、添加線程

threading_test.py

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_test.py
@time: 18/8/25 09:14
"""

import threading

# 獲取已激活的線程數
# print(threading.active_count())

# 查看所有線程信息
# print(threading.enumerate())

# 查看現在正在運行的線程
# print(threading.current_thread())

def thread_job():
    print("This is a thread of %s" % threading.current_thread())


def main():
    thread = threading.Thread(target=thread_job,)  # 定義線程
    thread.start() # 讓線程開始工作

if __name__ == "__main__":
    main()
2、join功能 不加 join() 的結果

我們讓 T1 線程工作的耗時增加

threading_join.py

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_join.py
@time: 18/8/25 09:14
"""

import threading
import time

def thread_job():
    print("T1 start
")
    for i in range(10):
        time.sleep(0.1) # 任務時間0.1s
    print("T1 finish
")


def main():
    added_thread = threading.Thread(target=thread_job, name="T1")  # 定義線程
    added_thread.start() # 讓線程開始工作
    print("all done
")

if __name__ == "__main__":
    main()

預想中輸出的結果是按照順序依次往下執行:

T1 start
T1 finish
all done

但實際運行結果為:

?  baseLearn python threading/threading_join.py
T1 start
all done


T1 finish

?  baseLearn
加入join()的結果

線程任務還未完成便輸出all done。如果要遵循順序,可以在啟動線程后對它調用join

added_thread.start()
added_thread.join()
print("all done
")

打印結果:

?  baseLearn python threading/threading_join.py
T1 start

T1 finish

all done

完整腳本文件:

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_join.py
@time: 18/8/25 09:14
"""

import threading
import time

def thread_job():
    print("T1 start
")
    for i in range(10):
        time.sleep(0.1) # 任務時間0.1s
    print("T1 finish
")


def main():
    added_thread = threading.Thread(target=thread_job, name="T1")  # 定義線程
    added_thread.start() # 讓線程開始工作
    added_thread.join()
    print("all done
")

if __name__ == "__main__":
    main()

小試牛刀

如果添加兩個線程,打印的輸出結果是怎樣的呢?

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_join.py
@time: 18/8/25 09:14
"""

import threading
import time

def T1_job():
    print("T1 start
")
    for i in range(10):
        time.sleep(0.1) # 任務時間0.1s
    print("T1 finish
")

def T2_job():
    print("T2 start
")
    print("T2 finish
")

def main():
    thread_1 = threading.Thread(target=T1_job, name="T1")  # 定義線程
    thread_2 = threading.Thread(target=T2_job, name="T2")  # 定義線程
    thread_1.start()  # 開啟T1
    thread_2.start()  # 開啟T2
    print("all done
")

if __name__ == "__main__":
    main()

輸出的”一種”結果是:

T1 start

T2 start

T2 finish

all done

T1 finish

現在T1和T2都沒有join,注意這里說”一種”是因為all done的出現完全取決于兩個線程的執行速度, 完全有可能T2 finish出現在all done之后。這種雜亂的執行方式是我們不能忍受的,因此要使用join加以控制。

我們試試在T1啟動后,T2啟動前加上thread_1.join():

thread_1.start()
thread_1.join() # notice the difference!
thread_2.start()
print("all done
")

打印結果:

T1 start

T1 finish

T2 start
all done

T2 finish

可以看到,T2會等待T1結束后才開始運行。

3、儲存進程結果Queue 實現功能

代碼實現功能,將數據列表中的數據傳入,使用四個線程處理,將結果保存在Queue中,線程執行完后,從Queue中獲取存儲的結果

在多線程函數中定義一個Queue,用來保存返回值,代替return,定義一個多線程列表,初始化一個多維數據列表,用來處理:

threading_queue.py

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_queue.py
@time: 18/8/25 09:14
"""

import threading
import time
from queue import Queue

def job(l, q):
    for i in range(len(l)):
        l[i] = l[i] ** 2
    q.put(l) #多線程調用的函數不能用return返回值

def multithreading():
    q = Queue()  #q中存放返回值,代替return的返回值
    threads = []
    data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]

    for i in range(4): #定義四個線程
        t = threading.Thread(target=job, args=(data[i], q))  #Thread首字母要大寫,被調用的job函數沒有括號,只是一個索引,參數在后面
        t.start() #開始線程
        threads.append(t) #把每個線程append到線程列表中

    for thread in threads:
        thread.join()

    results = []
    for _ in range(4):
        results.append(q.get()) #q.get()按順序從q中拿出一個值
    print(results)


if __name__ == "__main__":
    multithreading()

執行上邊的腳本出現了這樣的錯誤:

?  baseLearn python threading/threading_queue.py
Traceback (most recent call last):
  File "threading/threading_queue.py", line 11, in 
    from queue import Queue
ImportError: No module named queue

查了下原因,是因為python版本導致的:
解決方法:No module named "Queue"

On Python 2, the module is named Queue, on Python 3, it was renamed to follow PEP8 guidelines (all lowercase for module names), making it queue. The class remains Queue on all versions (following PEP8).

Typically, the way you"d write version portable imports would be to do:

python3 中這樣引用:

try:
    import queue
except ImportError:
    import Queue as queue

在 python2 中 我們可以這樣引用:

from Queue import Queue

打印:

baseLearn python ./threading/threading_queue.py
[[1, 4, 9], [9, 16, 25], [16, 16, 16], [25, 25, 25]]

完整代碼:
threading_queue.py

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_queue.py
@time: 18/8/25 09:14
"""

import threading
# import time
from Queue import Queue

def job(l, q):
    for i in range(len(l)):
        l[i] = l[i] ** 2
    q.put(l) #多線程調用的函數不能用return返回值

def multithreading():
    q = Queue()  #q中存放返回值,代替return的返回值
    threads = []
    data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]

    for i in range(4): #定義四個線程
        t = threading.Thread(target=job, args=(data[i], q))  #Thread首字母要大寫,被調用的job函數沒有括號,只是一個索引,參數在后面
        t.start() #開始線程
        threads.append(t) #把每個線程append到線程列表中

    for thread in threads:
        thread.join()

    results = []
    for _ in range(4):
        results.append(q.get()) #q.get()按順序從q中拿出一個值
    print(results)


if __name__ == "__main__":
    multithreading()
4、GIL效率問題 何為 GIL?

這次我們來看看為什么說 python 的多線程 threading 有時候并不是特別理想. 最主要的原因是就是, Python 的設計上, 有一個必要的環節, 就是 Global Interpreter Lock (GIL)。 這個東西讓 Python 還是一次性只能處理一個東西。

GIL的解釋:

盡管Python完全支持多線程編程, 但是解釋器的C語言實現部分在完全并行執行時并不是線程安全的。 實際上,解釋器被一個全局解釋器鎖保護著,它確保任何時候都只有一個Python線程執行。 GIL最大的問題就是Python的多線程程序并不能利用多核CPU的優勢 (比如一個使用了多個線程的計算密集型程序只會在一個單CPU上面運行)。
在討論普通的GIL之前,有一點要強調的是GIL只會影響到那些嚴重依賴CPU的程序(比如計算型的)。 如果你的程序大部分只會涉及到I/O,比如網絡交互,那么使用多線程就很合適, 因為它們大部分時間都在等待。實際上,你完全可以放心的創建幾千個Python線程, 現代操作系統運行這么多線程沒有任何壓力,沒啥可擔心的。
測試GIL

我們創建一個 job, 分別用 threading 和 一般的方式執行這段程序. 并且創建一個 list 來存放我們要處理的數據. 在 Normal 的時候, 我們這個 list 擴展4倍, 在 threading 的時候, 我們建立4個線程, 并對運行時間進行對比.

threading_gil.py

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_gil.py
@time: 18/8/25 09:14
"""

import threading
from Queue import Queue
import copy
import time

def job(l, q):
    res = sum(l)
    q.put(l) #多線程調用的函數不能用return返回值

def multithreading(l):
    q = Queue()  #q中存放返回值,代替return的返回值
    threads = []

    for i in range(4): #定義四個線程
        t = threading.Thread(target=job, args=(copy.copy(l), q), name="T%i" % i)  #Thread首字母要大寫,被調用的job函數沒有括號,只是一個索引,參數在后面
        t.start() #開始線程
        threads.append(t) #把每個線程append到線程列表中

    [t.join() for t in threads]
    total = 0
    for _ in range(4):
        total = q.get() #q.get()按順序從q中拿出一個值
    print(total)

def normal(l):
    total = sum(l)
    print(total)

if __name__ == "__main__":
    l = list(range(1000000))
    s_t = time.time()
    normal(l*4)
    print("normal:", time.time() - s_t)
    s_t = time.time()
    multithreading(l)
    print("multithreading: ", time.time() - s_t)

如果你成功運行整套程序, 你大概會有這樣的輸出. 我們的運算結果沒錯, 所以程序 threading 和 Normal 運行了一樣多次的運算. 但是我們發現 threading 卻沒有快多少, 按理來說, 我們預期會要快3-4倍, 因為有建立4個線程, 但是并沒有. 這就是其中的 GIL 在作怪.

1999998000000
normal:  0.10034608840942383
1999998000000
multithreading:  0.08421492576599121
5、線程鎖Lock 不使用 Lock 的情況

threading_lock.py

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_lock.py
@time: 18/8/25 09:14
"""

import threading

# 全局變量A的值每次加1,循環10次,并打印
def job1():
    global A
    for i in range(10):
        A+=1
        print("job1",A)

# 全局變量A的值每次加10,循環10次,并打印
def job2():
    global A
    for i in range(10):
        A+=10
        print("job2",A)

# 定義兩個線程,分別執行函數一和函數二
if __name__== "__main__":
   
    A=0
    t1=threading.Thread(target=job1)
    t2=threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

打印輸出數據:

?  baseLearn python ./threading/threading_lock.py
("job1", ("job2"1)
, (11)"job1"
("job2", 22)
("job2", 32)
("job2", 42)
("job2", 52)
("job2", 62)
("job2", 72)
("job2", 82)
("job2", 92)
("job2", 102)
, 12)
("job1", 103)
("job1", 104)
("job1", 105)
("job1", 106)
("job1", 107)
("job1", 108)
("job1", 109)
("job1", 110)

可以看出,打印的結果非常混亂

使用 Lock 的情況

lock在不同線程使用同一共享內存時,能夠確保線程之間互不影響,使用lock的方法是, 在每個線程執行運算修改共享內存之前,執行lock.acquire()將共享內存上鎖, 確保當前線程執行時,內存不會被其他線程訪問,執行運算完畢后,使用lock.release()將鎖打開, 保證其他的線程可以使用該共享內存。

函數一和函數二加鎖

def job1():
    global A,lock
    lock.acquire()
    for i in range(10):
        A+=1
        print("job1",A)
    lock.release()

def job2():
    global A,lock
    lock.acquire()
    for i in range(10):
        A+=10
        print("job2",A)
    lock.release()

主函數中定義一個Lock

if __name__== "__main__":
    lock=threading.Lock()
    A=0
    t1=threading.Thread(target=job1)
    t2=threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

完整代碼:

# -*- coding:utf-8 -*-

"""
@author: Corwien
@file: threading_lock.py
@time: 18/8/25 09:14
"""

import threading

def job1():
    global A,lock
    lock.acquire()
    for i in range(10):
        A+=1
        print("job1",A)
    lock.release()

def job2():
    global A,lock
    lock.acquire()
    for i in range(10):
        A+=10
        print("job2",A)
    lock.release()

if __name__== "__main__":
    lock = threading.Lock()
    A=0
    t1=threading.Thread(target=job1)
    t2=threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

打印輸出:

?  baseLearn python ./threading/threading_lock.py
("job1", 1)
("job1", 2)
("job1", 3)
("job1", 4)
("job1", 5)
("job1", 6)
("job1", 7)
("job1", 8)
("job1", 9)
("job1", 10)
("job2", 20)
("job2", 30)
("job2", 40)
("job2", 50)
("job2", 60)
("job2", 70)
("job2", 80)
("job2", 90)
("job2", 100)
("job2", 110)

從打印結果來看,使用lock后,一個一個線程執行完。使用lock和不使用lock,最后打印輸出的結果是不同的。


文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42316.html

相關文章

  • python綜合學習之多進程

    摘要:本節講學習的多進程。和之前的的不同點是丟向的函數有返回值,而的沒有返回值。所以接下來讓我們來看下這兩個進程是否會出現沖突。 本節講學習Python的多進程。 一、多進程和多線程比較 多進程 Multiprocessing 和多線程 threading 類似, 他們都是在 python 中用來并行運算的. 不過既然有了 threading, 為什么 Python 還要出一個 multip...

    gityuan 評論0 收藏0
  • Python爬蟲學習路線

    摘要:以下這些項目,你拿來學習學習練練手。當你每個步驟都能做到很優秀的時候,你應該考慮如何組合這四個步驟,使你的爬蟲達到效率最高,也就是所謂的爬蟲策略問題,爬蟲策略學習不是一朝一夕的事情,建議多看看一些比較優秀的爬蟲的設計方案,比如說。 (一)如何學習Python 學習Python大致可以分為以下幾個階段: 1.剛上手的時候肯定是先過一遍Python最基本的知識,比如說:變量、數據結構、語法...

    liaoyg8023 評論0 收藏0
  • 零基礎如何學爬蟲技術

    摘要:楚江數據是專業的互聯網數據技術服務,現整理出零基礎如何學爬蟲技術以供學習,。本文來源知乎作者路人甲鏈接楚江數據提供網站數據采集和爬蟲軟件定制開發服務,服務范圍涵蓋社交網絡電子商務分類信息學術研究等。 楚江數據是專業的互聯網數據技術服務,現整理出零基礎如何學爬蟲技術以供學習,http://www.chujiangdata.com。 第一:Python爬蟲學習系列教程(來源于某博主:htt...

    KunMinX 評論0 收藏0
  • jvm基礎篇一之內存區域

    摘要:堆區堆是虛擬機所管理的內存中最大的一塊,它是被所有線程共享的一塊內存區域,該區域在虛擬機啟動的時候創建。 運行時數據區域 ? ?想要了解jvm,那對其內存分配管理的學習是必不可少的;java虛擬機在執行java程序的時候會把它所管理的內存劃分成若干數據區域。這些區域有著不同的功能、用途、創建/銷毀時間。java虛擬機所分配管理的內存區域如圖1所示 程序計數器 ? ?程序計數器是一塊比較...

    Zachary 評論0 收藏0
  • Python爬蟲之多線程下載豆瓣Top250電影圖片

    摘要:本次爬蟲項目將會用到模塊中的類,多線程豆瓣電影圖片。總結通過上述兩個爬蟲程序的對比,我們不難發現,同樣是下載豆瓣電影,個網頁中的圖片,在沒有使用多線程的情況下,總共耗時約,而在使用多線程個線程的情況下,總共耗時約秒,效率整整提高了約倍。 爬蟲項目介紹 ??本次爬蟲項目將爬取豆瓣Top250電影的圖片,其網址為:https://movie.douban.com/top250, 具體頁面如...

    shiyang6017 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<