condition版生产者与消费者模式

news/2024/7/19 9:24:07 标签: 数据库, 爬虫

1.简介

爬虫中,生产者与消费者模式是经常用到的。我能想到的比较好的办法是使用redis或者mongodb数据库构造生产者消费者模型。如果直接起线程进行构造生产者消费者模型,线程容易假死,也难以构造复杂的生产者消费者模型。这里提供的condition版其实是最基本的生产者消费者模型的改良版,为了保护数据安全依旧是要开锁进行操作,但是不会循环的一直开锁,而是一旦条件不符合,则会阻塞,直到符合运行程序的条件。但是还是太low,不过这种思路值得借鉴。

2.代码

#  -*-coding:utf8 -*-

import threading

# Lock版本的生产者消费者模式可以正常的运行,但是太消耗CPU资源。
# 使用while循环的方式一直开锁解锁,很消耗资源。threading.Condition可以看作Lock的改良版
# 还有一个更好的模式就是用threading.Condition来实现
# threading.Condition可以在没有数据的时候处于阻塞等待状态,一旦有合适的数据了,
# 还可以使用notify相关的函数来通知其他处于等待状态的线程。这样就可以不用做一些无用的上锁
# 和解锁的操作,可以提高程序的性能。

# 1.acquire:获取锁
# 2.release:解锁
# 3.wait:释放内部占用的锁,同时线程被挂起。可以被其他线程用notify和notify_all函数唤醒,
# 被唤醒后会继续等待获取锁,获取锁后继续执行下面的代码
# 4.notify:唤醒一个挂起的线程,默认是第一个等待的线程。注意:notify不会释放所占用的锁
# 5.notify_all:通知所有正在等待的线程。notify和notify_all不会释放锁。并且需要在release之前调用

#  -*-coding:utf8 -*-
import threading
import random
import time

gMoney = 1000
gCondition = threading.Condition()
gTimes = 0
gTotalTimes = 30


class Producer(threading.Thread):
    def run(self):
        global gMoney
        global gTimes
        while True:
            money = random.randint(100, 1000)
            gCondition.acquire()
            if gTimes >= gTotalTimes:
                gCondition.release()
                break
            gMoney += money
            gTimes += 1
            print('%s生产了%s元钱,剩余%s元钱' % (threading.current_thread(), money, gMoney))
            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 gTimes >= gTotalTimes:
                    gCondition.release()
                    return
                # 当不满足条件时,直接进入阻塞,不在循环开锁,关锁的消耗资源的操作
                gCondition.wait()
            gMoney -= money
            print('%s消费了%d元钱,剩余%d元钱' % (threading.current_thread(), money, gMoney))
            gCondition.release()
            time.sleep(0.5)


def main():
    for x in range(5):
        t = Consumer(name='消费者线程%s' % x)
        t.start()
    for x in range(2):
        t = Producer(name='生产者线程%s' % x)
        t.start()


if __name__ == '__main__':
    main()
View Code

 

转载于:https://www.cnblogs.com/xufengnian/p/10788204.html


http://www.niftyadmin.cn/n/1719945.html

相关文章

C++ vector < vector> (tcy)

1.1.说明&#xff1a;1&#xff09;自动实现动态内存分配与释放&#xff0c;不用new和delete使得内存分配与释放更加安全元素是连续存储&#xff0c;可通过迭代器访问元素&#xff0c;可用指针偏移量来访问2&#xff09;当vector对象不为const时&#xff0c;const_iterator对象…

C++ std::deque (tcy)

1.1.特点&#xff1a;在头尾安插元素十分迅速。 在中间安插元素比较费时因为必须移动其它元素1.2.说明&#xff1a;双端队列是一个索引序列容器&#xff0c;允许在首尾快速插入和删除。在双端队列两端插入和删除绝不会使指向其余元素的指针或引用无效。双端队列元素不是连续存储…

装修注意事项

1. 空调孔位置: 三个挂机孔中心距到房顶都是25CM&#xff0c;在电器城问了一圈&#xff0c;都说至少要35CM左右才行。

C++20 decltype,decltype(auto) (tcy)

一.decltype说明符 1.1.语法&#xff1a;decltype (实体或表达式)//返回表达式的类型-必须加括号 1.2.用途&#xff1a;检查实体的声明类型或表达式的类型和值类别,函数返回值后置推导编译时类型推导,函数返回值后置推导 1.3.说明&#xff1a; 1&#xf…

http://www.eoeandroid.com/thread-9633-1-1.html

http://www.eoeandroid.com/thread-9633-1-1.html

点散射方法进行混响仿真,信号为单频信号,散射体高斯分布,无多普勒频域...

clc;close all;clear all; %点散射方法进行混响仿真&#xff0c;信号为单频信号&#xff0c;散射体高斯分布&#xff0c;无多普勒频域 M100; %阵元数 N1000; deltar1; %每次扫描的角度 deltasita1; p(deltar)*(deltasita)/(2*pi); f025000; fs150000; c1500; T0.02; …

Bitmap的一些操作

这个不同于ImageView控件&#xff0c;这个不是控件&#xff0c;是画在画布上的&#xff0c;类要继承与View。将图片导入到res文件夹的三个文件下面。 得到资源 得到图片的方式为&#xff1a; myPic1((BitmapDrawable)getResources();getDrawable(R.drawable.p1)).getBitmap()…

C++ std::declval <utility> (tcy)

1.1.定义&#xff1a;template<class T> typename std::add_rvalue_reference<T>::type declval() noexcept; (since C11) 1.2.用途&#xff1a;将任何类型转为引用类型&#xff0c;从而可用在decltype表达式而无需通过构造函数 1.3.说明&…