理解 Python 中的多线程
1、單線程
import time import urllib2def get_responses():urls = ['http://www.google.com','http://www.amazon.com','http://www.ebay.com','http://www.alibaba.com','http://www.reddit.com']start = time.time()for url in urls:print urlresp = urllib2.urlopen(url)print resp.getcode()print "Elapsed time: %s" % (time.time()-start)get_responses()解釋:
url順序的被請求?
除非cpu從一個url獲得了回應,否則不會去請求下一個url?
網絡請求會花費較長的時間,所以cpu在等待網絡請求的返回時間內一直處于閑置狀態。
2、多線程
import urllib2 import time from threading import Threadclass GetUrlThread(Thread):def __init__(self, url):self.url = url super(GetUrlThread, self).__init__()def run(self):resp = urllib2.urlopen(self.url)print self.url, resp.getcode()def get_responses():urls = ['http://www.google.com', 'http://www.amazon.com', 'http://www.ebay.com', 'http://www.alibaba.com', 'http://www.reddit.com']start = time.time()threads = []for url in urls:t = GetUrlThread(url)threads.append(t)t.start()for t in threads:t.join()print "Elapsed time: %s" % (time.time()-start)get_responses()解釋:?
意識到了程序在執行時間上的提升?
我們寫了一個多線程程序來減少cpu的等待時間,當我們在等待一個線程內的網絡請求返回時,這時cpu可以切換到其他線程去進行其他線程內的網絡請求。?
我們期望一個線程處理一個url,所以實例化線程類的時候我們傳了一個url。?
線程運行意味著執行類里的run()方法。?
無論如何我們想每個線程必須執行run()。?
為每個url創建一個線程并且調用start()方法,這告訴了cpu可以執行線程中的run()方法了。?
我們希望所有的線程執行完畢的時候再計算花費的時間,所以調用了join()方法。?
join()可以通知主線程等待這個線程結束后,才可以執行下一條指令。?
每個線程我們都調用了join()方法,所以我們是在所有線程執行完畢后計算的運行時間。?
關于線程:?
cpu可能不會在調用start()后馬上執行run()方法。?
你不能確定run()在不同線程建間的執行順序。?
對于單獨的一個線程,可以保證run()方法里的語句是按照順序執行的。?
這就是因為線程內的url會首先被請求,然后打印出返回的結果。
解決資源競爭
from threading import Lock, Thread lock = Lock() some_var = 0class IncrementThread(Thread):def run(self):#we want to read a global variable#and then increment itglobal some_varlock.acquire()read_value = some_varprint "some_var in %s is %d" % (self.name, read_value)some_var = read_value + 1print "some_var in %s after increment is %d" % (self.name, some_var)lock.release()def use_increment_thread():threads = []for i in range(50):t = IncrementThread()threads.append(t)t.start()for t in threads:t.join()print "After 50 modifications, some_var should have become 50"print "After 50 modifications, some_var is %d" % (some_var,)use_increment_thread()解釋:?
Lock 用來防止競爭條件?
如果在執行一些操作之前,線程t1獲得了鎖。其他的線程在t1釋放Lock之前,不會執行相同的操作?
我們想要確定的是一旦線程t1已經讀取了some_var,直到t1完成了修改some_var,其他的線程才可以讀取some_var?
這樣讀取和修改some_var成了邏輯上的原子操作
加鎖保證操作的原子性
from threading import Thread, Lock import timelock = Lock()class CreateListThread(Thread):def run(self):self.entries = []for i in range(10):time.sleep(0.01)self.entries.append(i)lock.acquire()print self.entrieslock.release()def use_create_list_thread():for i in range(3):t = CreateListThread()t.start()use_create_list_thread()證明了一個線程不可以修改其他線程內部的變量(非全局變量)。
Python多線程簡易版:線程池 threadpool
import threadpool import time import urllib2urls = ['http://www.google.com', 'http://www.amazon.com', 'http://www.ebay.com', 'http://www.alibaba.com', 'http://www.reddit.com' ]def myRequest(url):resp = urllib2.urlopen(url)print url, resp.getcode()def timeCost(request, n):print "Elapsed time: %s" % (time.time()-start)start = time.time() pool = threadpool.ThreadPool(5) reqs = threadpool.makeRequests(myRequest, urls, timeCost) [ pool.putRequest(req) for req in reqs ] pool.wait()makeRequests創建了要開啟多線程的函數,以及函數相關參數和回調函數,其中回調函數可以不寫,default是無,也就是說makeRequests只需要2個參數就可以運行;
注意:threadpool 是非線程安全的。
?
轉載于:https://www.cnblogs.com/zhaojihui/p/7284721.html
總結
以上是生活随笔為你收集整理的理解 Python 中的多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 欧加自贸协定“难产” 物联网安全受关注
- 下一篇: websocket python爬虫_p