理解 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順序的被請(qǐng)求?
除非cpu從一個(gè)url獲得了回應(yīng),否則不會(huì)去請(qǐng)求下一個(gè)url?
網(wǎng)絡(luò)請(qǐng)求會(huì)花費(fèi)較長(zhǎng)的時(shí)間,所以cpu在等待網(wǎng)絡(luò)請(qǐng)求的返回時(shí)間內(nèi)一直處于閑置狀態(tài)。
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()解釋:?
意識(shí)到了程序在執(zhí)行時(shí)間上的提升?
我們寫(xiě)了一個(gè)多線程程序來(lái)減少cpu的等待時(shí)間,當(dāng)我們?cè)诘却粋€(gè)線程內(nèi)的網(wǎng)絡(luò)請(qǐng)求返回時(shí),這時(shí)cpu可以切換到其他線程去進(jìn)行其他線程內(nèi)的網(wǎng)絡(luò)請(qǐng)求。?
我們期望一個(gè)線程處理一個(gè)url,所以實(shí)例化線程類(lèi)的時(shí)候我們傳了一個(gè)url。?
線程運(yùn)行意味著執(zhí)行類(lèi)里的run()方法。?
無(wú)論如何我們想每個(gè)線程必須執(zhí)行run()。?
為每個(gè)url創(chuàng)建一個(gè)線程并且調(diào)用start()方法,這告訴了cpu可以執(zhí)行線程中的run()方法了。?
我們希望所有的線程執(zhí)行完畢的時(shí)候再計(jì)算花費(fèi)的時(shí)間,所以調(diào)用了join()方法。?
join()可以通知主線程等待這個(gè)線程結(jié)束后,才可以執(zhí)行下一條指令。?
每個(gè)線程我們都調(diào)用了join()方法,所以我們是在所有線程執(zhí)行完畢后計(jì)算的運(yùn)行時(shí)間。?
關(guān)于線程:?
cpu可能不會(huì)在調(diào)用start()后馬上執(zhí)行run()方法。?
你不能確定run()在不同線程建間的執(zhí)行順序。?
對(duì)于單獨(dú)的一個(gè)線程,可以保證run()方法里的語(yǔ)句是按照順序執(zhí)行的。?
這就是因?yàn)榫€程內(nèi)的url會(huì)首先被請(qǐng)求,然后打印出返回的結(jié)果。
解決資源競(jìng)爭(zhēng)
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 用來(lái)防止競(jìng)爭(zhēng)條件?
如果在執(zhí)行一些操作之前,線程t1獲得了鎖。其他的線程在t1釋放Lock之前,不會(huì)執(zhí)行相同的操作?
我們想要確定的是一旦線程t1已經(jīng)讀取了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()證明了一個(gè)線程不可以修改其他線程內(nèi)部的變量(非全局變量)。
Python多線程簡(jiǎn)易版:線程池 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創(chuàng)建了要開(kāi)啟多線程的函數(shù),以及函數(shù)相關(guān)參數(shù)和回調(diào)函數(shù),其中回調(diào)函數(shù)可以不寫(xiě),default是無(wú),也就是說(shuō)makeRequests只需要2個(gè)參數(shù)就可以運(yùn)行;
注意:threadpool 是非線程安全的。
?
轉(zhuǎn)載于:https://www.cnblogs.com/zhaojihui/p/7284721.html
總結(jié)
以上是生活随笔為你收集整理的理解 Python 中的多线程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 欧加自贸协定“难产” 物联网安全受关注
- 下一篇: java8-新特性default