[python爬蟲之路day13]:多線程——加速爬取數據

今天我們來介紹多線程。
進程裏有很多目標,多線程的目的簡言之就是加快進程,提高效率,多個操作同時進行。
下面來看代碼:
一.初識

import time
import threading

###############單線程##############################
 def coding():
     for x in range(3):
         print("正在玩孫尚香%s"%x)
         time.sleep(1)
 def codis():
     for x in range(3):
         print("正在玩孫權%s" %x)
         time.sleep(1)
 def main():
     coding()
     codis()
 if __name__ == '__main__':
     main()
######3##############多線程###########################
def coding():
    for x in range(3):
        print("正在玩孫尚香%s" % threading.current_thread())#打印當前線程的名字
        time.sleep(1)
def codis():
    for x in range(3):
        print("正在玩孫權%s" %  threading.current_thread())#打印當前線程的名字
        time.sleep(1)


def main():
    t1=threading.Thread(target=coding)#創建線程
    t2=threading.Thread(target=codis)#創建線程
    t1.start()
    t2.start()
    print(threading.enumerate())#打印所有線程的名字
if __name__ == '__main__':
    main()

#二.使用thread類創建多線程

#二.使用thread類創建多線程
 class CodingThread(threading.Thread):
#     def run(self):
#         for x in range(3):
#             print("正在玩孫尚香%s" % threading.current_thread())  # 打印當前線程的名字
             time.sleep(1)
 class DrawThread(threading.Thread):
     def run(self):
         for x in range(3):
             print("正在玩孫權%s" % threading.current_thread())
             time.sleep(1)
 def main():
     t1=CodingThread()
     t2=DrawThread()
     t1.start()
     t2.start()
 if __name__ == '__main__':
     main()

三.多線程共享全局變量及鎖機制

VALUE=0
gLook=threading.Lock()#鎖機制1
def add_value():
    global VALUE
    gLook.acquire()#鎖機制2
    for x in range(10000000):
        VALUE+=1
    gLook.release()#鎖機制3
    print(VALUE)
def main():
    for x in range(2):
        t1=threading.Thread(target=add_value)
        t1.start()
if __name__ == '__main__':
    main()

四.多線程實例(生產者與消費者模式)
lock版本

import time
import threading
import random
gMoney=1000
gLock=threading.Lock()
gtotalTimes=10
gTime=0
class Producer(threading.Thread):
    def run(self):
        global gMoney
        global gTime
        while True:
            money=random.randint(100,1000)
            gLock.acquire()
            if gTime>=gtotalTimes:
                gLock.release()
                break
            gMoney+=money
            print('%s生產了%d元,剩餘%d元錢'%(threading.current_thread(),money,gMoney))
            gTime+=1
            gLock.release()
            time.sleep(0.5)


class Consumer(threading.Thread):
    def run(self):
        global gMoney
        while True:
            money=random.randint(100,1000)
            gLock.acquire()
            if gMoney>=money:
                gMoney-=money
                print("%s消費了%d元,剩餘%d元"%(threading.current_thread(),money,gMoney))
            else:
                if gTime>=gtotalTimes:
                    gLock.release()
                    break
                print('%s消費者準備消費%d元,剩餘%d元,不足!'%(threading.current_thread(),money,gMoney))
            gLock.release()
            time.sleep(0.5)
def main():
    for x in range(3):
        t=Consumer(name='消費者線程%d'%x)
        t.start()
    for x in range(5):
        t=Producer(name='生產者線程%d'%x)
        t.start()

if __name__ == '__main__':
    main()

五.condition版本的消費者和生產者模式。
爲了克服lock版本對cpu的損耗,我們採用threading.condition

1.acquire上鎖
2.release解鎖
3.wait:將該線程處於等待狀態,並且會釋放鎖,可以被notify,notify_all喚醒。
4.notify通知某個在等待進程,默認爲第一個。
5.notify_all:通知所有在等待的進程,並且notify_all和notify不會解鎖,應該啊在release前調用。
下面來看代碼:

import time
import threading
import random
gMoney=1000
gCondition=threading.Condition()
gtotalTimes=10
gTime=0
class Producer(threading.Thread):
    def run(self):
        global gMoney
        global gTime
        while True:
            money=random.randint(100,1000)
            gCondition.acquire()
            if gTime>=gtotalTimes:
                gCondition.release()
                break
            gMoney+=money
            print('%s生產了%d元,剩餘%d元錢'%(threading.current_thread(),money,gMoney))
            gTime+=1
            gCondition.notify_all()#通知甦醒
            gCondition.release()
            time.sleep(0.5)


class Consumer(threading.Thread):
    def run(self):
        global gMoney
        while True:
            money=random.randint(100,1000)
            gCondition.acquire()
            while gMoney<money:
                if gTime>=gtotalTimes:
                    return
                print("%s準備消費%d元,剩餘%d元,不足!"%(threading.current_thread(),money,gMoney))
                gCondition.wait()
            print('%s消費了%d元,剩餘%d元'%(threading.current_thread(),money,gMoney))
            gCondition.release()
            time.sleep(0.5)
def main():
    for x in range(3):
        t=Consumer(name='消費者線程%d'%x)
        t.start()
    for x in range(5):
        t=Producer(name='生產者線程%d'%x)
        t.start()

if __name__ == '__main__':
    main()

Queue線程安全隊列
加鎖是個經常的過程,如果你想把一些數據存儲到某個隊列,python內置queue模塊,其中Queue(先進先出),LiFoQueue(後進先出),可在多線程中使用,實現線程的同步。
1.q=Queue(3)#初始化創建一個先進先出隊列。
2.qsize(),返回隊列的大小。
3.empty()判斷是否爲空。
4.full() 判斷是否滿。
5.get() 按隊列規則取出數據。
6.put(),將數據放入隊列中。
下面看代碼:

from queue import Queue
import time
import threading
q=Queue(4)
# print(q.qsize())
# print(q.empty())
# for x in range(4):
#     q.put(x)
#     print()
# print(q.full())
# for x in range(4):
#     print(q.get())
def set_value(q):
    index=0
    while True:
        q.put(index)
        index+=1
        time.sleep(3)
def get_valuee(q):
    while True:
        print(q.get())
def main():
    q=Queue(4)
    t1=threading.Thread(target=set_value,args=[q])
    t2=threading.Thread(target=get_valuee,args=[q])
    t1.start()
    t2.start()
if __name__ == '__main__':
    main()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章