Python爬虫11-多线程同步问题

一、线程中的资源竞争

import threading
import time
num = 0
# 创建一把锁 默认是没有上锁
suo=threading.Lock()
def demo1(nums):
    global num
    # 加锁
    suo.acquire()
    for i in range(nums):
        num += 1
    # 解锁
    suo.release()
    print('demo1-num %d'%num)
def demo2(nums):
    global num
    # 加锁
    suo.acquire()
    for i in range(nums):
        num += 1
    # 解锁
    suo.release()
    print('demo2-num %d'%num)
def main():
    t1=threading.Thread(target=demo1,args=(1000000,))
    t2=threading.Thread(target=demo2,args=(1000000,))
    t1.start()
    # t1.join()
    # time.sleep(1)
    t2.start()
    # t1.join()
    time.sleep(1)
    print('demo-num %d'%num)

if __name__ == '__main__':
    main()

threading.Lock() 只能创建一次
threading.RLock() 可创建多次,需逐个解锁

二、死锁

import threading
import time

class MyThread1(threading.Thread):
    def run(self):
        # 对mutexA上锁
        mutexA.acquire()

        # mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁
        print(self.name+'----do1---up----')
        time.sleep(1)

        # 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了
        mutexB.acquire()
        print(self.name+'----do1---down----')
        mutexB.release()

        # 对mutexA解锁
        mutexA.release()

class MyThread2(threading.Thread):
    def run(self):
        # 对mutexB上锁
        mutexB.acquire()

        # mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁
        print(self.name+'----do2---up----')
        time.sleep(1)

        # 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
        mutexA.acquire()
        print(self.name+'----do2---down----')
        mutexA.release()

        # 对mutexB解锁
        mutexB.release()

mutexA = threading.Lock()
mutexB = threading.Lock()

if __name__ == '__main__':
    t1 = MyThread1()
    t2 = MyThread2()
    t1.start()
    t2.start()
# Thread-1----do1---up----
# Thread-2----do2---up----

三、Queue线程(队列)

队列:先进先出
empty():判断队列是否为空
full():判断队列是否满了

from queue import Queue
q=Queue(3)
print(q.empty())   # True 空的队列 False 不是空的队列
print(q.full())    # True 满的队列 False 不是满的队列

put():将一个数据放到队列中

q.put(1)
q.put(2)
q.put(3)
q.put(4,timeout=3)  # 队列已满,溢出,报错
# 或 q.put_nowait(4)

get():从队列中取最后一个数据

print(q.get())   # 1
print(q.get())   # 2
print(q.get())   # 3
print(q.get(timeout=3))  # 队列已空,报错
# 或 print(q.get_nowait())

四、线程同步

张三:李四同学
李四:在
张三:现在几点了?
李四:不知道!

import threading

创建2个线程

class ZhangSan(threading.Thread):
    def __init__(self,cond):
        super().__init__(name='张三')
        self.cond=cond

    def run(self):
        self.cond.acquire()   # 加锁

        print('{}:李四同学'.format(self.name))
        self.cond.notify()   # 唤醒

        self.cond.wait()     # 等待
        print('{}:现在几点了?'.format(self.name))
        self.cond.notify()   # 唤醒

        self.cond.release()   # 解锁
class LiSi(threading.Thread):
    def __init__(self,cond):
        super().__init__(name='李四')
        self.cond=cond

    def run(self):
        self.cond.acquire()   # 加锁

        self.cond.wait()      # 等待
        print('{}:在'.format(self.name))
        self.cond.notify()    # 唤醒

        self.cond.wait()      # 等待
        print('{}:不知道!'.format(self.name))

        self.cond.release()   # 解锁
if __name__ == '__main__':
    cond=threading.Condition()
    lisi=LiSi(cond)
    zhangsan=ZhangSan(cond)

    lisi.start()
    zhangsan.start()

五、生产者和消费者

生产者和消费者模式是多线程开发中常见的一种模式。通过生产者和消费者模式,可以让代码达到高内聚低耦合的目标,线程管理更加方便,程序分工更加明确。

5.1 Lock版的生产者和消费者

import threading
import random
import time
Gmoney=0
# 定义一个变量,保存生产的次数
Gtime=0
# 定义一把锁
lock=threading.Lock()
# 定义生产者
class Producer(threading.Thread):
    def run(self) -> None:
        global Gmoney
        global Gtime

        while True:
            lock.acquire()      # 加锁
            if Gtime >= 10:
                lock.release()  # 解锁
                break

            money = random.randint(0, 100)
            Gmoney += money
            Gtime += 1
            print('%s生产了%d元钱' % (threading.current_thread().name, money))
            lock.release()
            time.sleep(1)
# 定义消费者
class Consumer(threading.Thread):
    def run(self) -> None:
        global Gmoney
        global Gtime

        while True:
            lock.acquire()   # 加锁
            money = random.randint(0, 100)
            if Gmoney >= money:
                Gmoney -= money
                print('%s消费了%d元钱' % (threading.current_thread().name, money))
            else:
                if Gtime >= 10:
                    lock.release()  # 解锁
                    break
                print('%s消费了%d元钱,余额只有%d' % (threading.current_thread().name, money, Gmoney))
            lock.release()
            time.sleep(1)
def main():
    # 开启5个生产者
    for i in range(5):
        p=Producer(name='生产者%d号'%i)
        p.start()
    # 开启5个消费者
    for j in range(5):
        c=Consumer(name='消费者%d号'%j)
        c.start()

if __name__ == '__main__':
    main()

5.2 Condition版的生产者和消费者

import threading
import random
import time
Gmoney=0
# 定义一个变量,保存生产的次数
Gtime=0
cond=threading.Condition()
# 定义生产者
class Producer(threading.Thread):
    def run(self) -> None:
        global Gmoney
        global Gtime

        while True:
            cond.acquire()      # 加锁
            if Gtime >= 10:
                cond.release()  # 解锁
                break

            money = random.randint(0, 100)
            Gmoney += money
            Gtime += 1
            print('%s生产了%d元钱,剩余%d元' % (threading.current_thread().name, money,Gmoney))
            cond.notify_all()   # 唤醒所有
            cond.release()
            time.sleep(1)
# 定义消费者
class Consumer(threading.Thread):
    def run(self) -> None:
        global Gmoney
        global Gtime

        while True:
            cond.acquire()   # 加锁
            money = random.randint(0, 100)

            while Gmoney < money:
                if Gtime >= 10:
                    cond.release()
                    return   # 这里如果用break退出了内层循环,但是外层循环没有退出,直接用return
                print('%s消费者消费了%d元,余额%d元,生产者不再生成了'%(threading.current_thread().name,money,Gmoney))
                cond.wait()

            # 开始消费
            Gmoney -= money
            print('%s消费了%d元钱,剩余%d元' % (threading.current_thread().name, money,Gmoney))
            cond.release()
            time.sleep(1)
def main():
    # 开启5个生产者
    for i in range(5):
        p=Producer(name='生产者%d号'%i)
        p.start()
    # 开启5个消费者
    for j in range(5):
        c=Consumer(name='消费者%d号'%j)
        c.start()

if __name__ == '__main__':
    main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值