Python3線程中常用的兩個模塊為**
_thread
threading(推薦使用)
每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。
每個線程都有他自己的一組CPU寄存器,稱為線程的上下文,該上下文反映了線程上次運行該線程的CPU寄存器的狀態。
thread 模塊已被廢棄。用戶可以使用 threading 模塊代替。所以,在 Python3 中不能再使用"thread" 模塊。為了兼容性,Python3 將 thread 重命名為 “_thread”。
_thread模塊
#Python中調用_thread模塊中的start_new_thread()函數產生新線程。_thread的語法如下:
_thread.start_new._thread(function,args[,kwargs])
參數說明:
function - 線程函數。
args - 傳遞給線程函數的參數,他必須是個tuple類型。
kwargs - 可選參數。
#_thread模塊除了產生線程外,還提供基本同步數據結構鎖對象(lock object,也叫原語鎖、簡單鎖、互斥鎖、互斥量、二值信號量)。同步原語與線程管理是密不可分的。
案例1
import _thread
from time import sleep
from datetime import datetime
date_time_format='%y-%M-%d %H:%M:%S'
def date_time_str(date_time):
return datetime.strftime(date_time,date_time_format)
def loop_one():
print('+++線程一開始于:',date_time_str(datetime.now()))
print('+++線程一休眠4秒')
sleep(4)
print('+++線程一休眠結束,結束于:',date_time_str(datetime.now()))
def loop_two():
print('***線程二開始于:',date_time_str(datetime.now()))
print('***線程二休眠2秒')
sleep(2)
print('***線程二結束休眠,結束于:',date_time_str(datetime.now()))
def main():
print('-----所有線程開始時間:',date_time_str(datetime.now()))
_thread.start_new_thread(loop_one,())
_thread.start_new_thread(loop_two,())
sleep(6)
print('-----所有線程結束時間:',date_time_str(datetime.now()))
if __name__=='__main__':
main()
案例2
import _thread
import time
#為線程定義一個函數
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print ("%s: %s" % ( threadName, time.ctime(time.time()) ))
#創建兩個線程
try:
_thread.start_new_thread( print_time, ("Thread-1", 2, ) )
_thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print ("Error: 無法啟動線程")
while 1:
pass
#執行以上程后可以按下 ctrl-c to 退出。
#_thread模塊提供了簡單的多線程機制,兩個循環并發執行,總的運行時間為最慢的線程的運行時間(主線程6s),而不是所有線程的運行時間之和。start_new_thread()要求至少傳兩個參數,即使想要運行的函數不要參數,也要傳一個空元組。
#sleep(6)是讓主線程停下來。主線程一旦運行結束,就關閉運行著的其他兩個線程。這可能造成主線程過早或過晚退出,這時就要使用線程鎖,主線程可認在兩個子線程都退出后立即退出。
import _thread
from time import sleep
from datetime import datetime
loops=[4,2]
date_time_format='%y-%M-%d %H:%M:%S'
def date_time_str(date_time):
return datetime.strftime(date_time,date_time_format)
def loop(n_loop,n_sec,lock):
print('線程(',n_loop,')開始執行:,date_time_str(datetime.now()),先休眠(',n_sec,')秒')
sleep(n_sec)
print('線程(',n_loop,')休眠結束,結束于:',date_time_str(datetime.now()))
lock.release()
def main():
print('---所有線程開始執行...')
locks=[]
n_loops=range(len(loops))
for i in n_loops:
lock=_thread.allocate_lock()
lock.acquire()
locks.append(lock)
for i in n_loops:
_thread.start_new_thread(loop,(i,loops[i],locks[i]))
for i in n_loops:
while locks[i].locked():
pass
print('---所有線程執行結束:',date_time_str(datetime.now()))
if __name__=='__main__':
main()
線程模塊
Python3 通過兩個標準庫 _thread 和 threading 提供對線程的支持。
_thread 提供了低級別的、原始的線程以及一個簡單的鎖,它相比于 threading 模塊的功能還是比較有限的。
threading 模塊除了包含 _thread 模塊中的所有方法外,還提供的其他方法:
threading.currentThread(): 返回當前的線程變量。
threading.enumerate(): 返回一個包含正在運行的線程的list。正在運行指線程啟動后、結束前,不包括啟動前和終止后的線程。
threading.activeCount(): 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。
除了使用方法外,線程模塊同樣提供了Thread類來處理線程,Thread類提供了以下方法:
run(): 用以表示線程活動的方法。
start():啟動線程活動。
join([time]): 等待至線程中止。這阻塞調用線程直至線程的join() 方法被調用中止-正常退出或者拋出未處理的異常-或者是可選的超時發生。
isAlive(): 返回線程是否活動的。
getName(): 返回線程名。
setName(): 設置線程名。
使用 threading 模塊創建線程
我們可以通過直接從 threading.Thread 繼承創建一個新的子類,并實例化后調用 start() 方法啟動新線程,即它調用了線程的 run() 方法:
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("開始線程:" + self.name)
print_time(self.name, self.counter, 5)
print ("退出線程:" + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
threadName.exit()
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
# 創建新線程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 開啟新線程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("退出主線程")
線程同步
如果多個線程共同對某個數據修改,則可能出現不可預料的結果,為了保證數據的正確性,需要對多個線程進行同步。
使用 Thread 對象的 Lock 和 Rlock 可以實現簡單的線程同步,這兩個對象都有 acquire 方法和 release 方法,對于那些需要每次只允許一個線程操作的數據,可以將其操作放到 acquire 和 release 方法之間。如下:
多線程的優勢在于可以同時運行多個任務(至少感覺起來是這樣)。但是當線程需要共享數據時,可能存在數據不同步的問題。
考慮這樣一種情況:一個列表里所有元素都是0,線程"set"從后向前把所有元素改成1,而線程"print"負責從前往后讀取列表并打印。
那么,可能線程"set"開始改的時候,線程"print"便來打印列表了,輸出就成了一半0一半1,這就是數據的不同步。為了避免這種情況,引入了鎖的概念。
鎖有兩種狀態——鎖定和未鎖定。每當一個線程比如"set"要訪問共享數據時,必須先獲得鎖定;如果已經有別的線程比如"print"獲得鎖定了,那么就讓線程"set"暫停,也就是同步阻塞;等到線程"print"訪問完畢,釋放鎖以后,再讓線程"set"繼續。
經過這樣的處理,打印列表時要么全部輸出0,要么全部輸出1,不會再出現一半0一半1的尷尬場面。
實例:
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("開啟線程: " + self.name)
# 獲取鎖,用于線程同步
threadLock.acquire()
print_time(self.name, self.counter, 3)
# 釋放鎖,開啟下一個線程
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print ("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
threadLock = threading.Lock()
threads = []
# 創建新線程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 開啟新線程
thread1.start()
thread2.start()
# 添加線程到線程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有線程完成
for t in threads:
t.join()
print ("退出主線程")
線程優先級隊列( Queue)
Python 的 Queue 模塊中提供了同步的、線程安全的隊列類,包括FIFO(先入先出)隊列Queue,LIFO(后入先出)隊列LifoQueue,和優先級隊列 PriorityQueue。
這些隊列都實現了鎖原語,能夠在多線程中直接使用,可以使用隊列來實現線程間的同步。
Queue 模塊中的常用方法:
Queue.qsize() 返回隊列的大小
Queue.empty() 如果隊列為空,返回True,反之False
Queue.full() 如果隊列滿了,返回True,反之False
Queue.full 與 maxsize 大小對應
Queue.get([block[, timeout]])獲取隊列,timeout等待時間
Queue.get_nowait() 相當Queue.get(False)
Queue.put(item) 寫入隊列,timeout等待時間
Queue.put_nowait(item) 相當Queue.put(item, False)
Queue.task_done() 在完成一項工作之后,Queue.task_done()函數向任務已經完成的隊列發送一個信號
Queue.join() 實際上意味著等到隊列為空,再執行別的操作
import queue
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self):
print ("開啟線程:" + self.name)
process_data(self.name, self.q)
print ("退出線程:" + self.name)
def process_data(threadName, q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print ("%s processing %s" % (threadName, data))
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1
#創建新線程
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
#填充隊列
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
#等待隊列清空
while not workQueue.empty():
pass
#通知線程是時候退出
exitFlag = 1
#等待所有線程完成
for t in threads:
t.join()
print ("退出主線程")
python之多線程
https://www.cnblogs.com/smallmars/p/7149507.html
#coding=utf-8
import threading # 導入threading包
from time import sleep
import time
def task1():
print("Task 1 executed.")
sleep(1)
def task2():
print("Task 2 executed.")
sleep(5)
print("多線程:")
starttime = time.time(); # 記錄開始時間
threads = [] # 創建一個線程列表,用于存放需要執行的子線程
t1 = threading.Thread(target=task1) # 創建第一個子線程,子線程的任務是調用task1函數,注意函數名后不能有()
threads.append(t1) # 將這個子線程添加到線程列表中
t2 = threading.Thread(target=task2) # 創建第二個子線程
threads.append(t2) # 將這個子線程添加到線程列表中
for t in threads: # 遍歷線程列表
t.setDaemon(True) # 將線程聲明為守護線程,必須在start() 方法調用之前設置,如果不設置為守護線程程序會被無限掛起
t.start() # 啟動子線程
endtime = time.time(); # 記錄程序結束時間
totaltime = endtime - starttime; # 計算程序執行耗時
print("耗時:{0:.5f}秒".format(totaltime)); # 格式輸出耗時
print('---------------------------')
#以下為普通的單線程執行過程,不需解釋
print("單線程:")
starttime = time.time();
task1();
task2();
endtime = time.time();
totaltime = endtime - starttime;
print("耗時:{0:.5f}秒".format(totaltime));
偽裝好了才能出發,通過proxy代理IP訪問網站,python爬蟲(1)
from urllib.request import Request, build_opener
from fake_useragent import UserAgent
from urllib.request import ProxyHandler
url = "http://httpbin.org/get"
headers={
"User-Agent": UserAgent().chrome
}
request = Request(url, headers=headers)
handler = ProxyHandler({"http" : "112.85.129.8:9999"})
opener = build_opener(handler)
response = opener.open(request)
print(response.read().decode())
通過ajax請求獲得信息,沒想到應用范圍如此廣,python爬蟲(2)
from urllib.request import Request, urlopen
from fake_useragent import UserAgent
base_url ="https://movie.douban.com/j/search_subjects?type=tv&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start={}"
i = 0
while True:
headers = {
"User-Agent": UserAgent().chrome
}
url = base_url.format(i * 20)
request = Request(url, headers=headers)
response = urlopen(request)
info = response.read().decode()
print(info)
if info == "" or info is None or i==10:
print("got all of data")
break
i += 1
print("get "+ str(i) + " page")
3分鐘搞定一個爬蟲,貼吧爬蟲就是這么簡單,python爬蟲(3)
from urllib.request import Request, urlopen
from urllib.parse import urlencode
from fake_useragent import UserAgent
def get_html(url):
headers = {
"User-Agent": UserAgent().chrome
}
request =Request(url, headers=headers)
response = urlopen(request)
print(response.read().decode())
return response.read()
def save_html(filename, html_bytes):
with open(filename, "wb" ) as f:
f.write(html_bytes)
def main():
content = input("下載內容:")
number = input("下載頁面:")
base_url = "https://tieba.baidu.com/f?ie=utf-8&{}"
for pn in range(int(number)):
args = {
"pn": pn*50,
"kw": content
}
args = urlencode(args)
filename = "第" + str(pn) + "頁.html"
print("正在下載"+filename)
html_bytes = get_html(base_url.format(args))
save_html(filename, html_bytes)
if __name__ == '__main__':
main()
request請求中進行url轉碼,結果意想不到,python爬蟲(4)
from urllib.request import Request, urlopen
from urllib.parse import urlencode
parameters={"wd":"你好"}
url = "https://www.baidu.com/s?wd={}".format(urlencode(parameters))
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"}
request = Request(url, headers=headers)
response = urlopen(request)
print(response.read().decode())
閑著會生病的,玩玩python吧,python爬蟲(5)
from urllib.request import urlopen
from urllib.request import Request
from random import choice
url = "http://www.baidu.com"
user_agents = [
"Mozilla/5.0(compatible;MSIE9.0;WindowsNT6.1;Trident/5.0",
"Opera/9.80(WindowsNT6.1;U;en)Presto/2.8.131Version/11.11",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"]
headers = {"User-Agent": choice(user_agents)}
request = Request(url, headers=headers)
print(request.get_header('User-agent'))
response = urlopen(request)
info = response.read()
#print(info)
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
