[Python]多线程编程&线程间共享变量&消费者生产者问题的解决
来源:互联网 发布:linux setlocale 编辑:程序博客网 时间:2024/06/05 02:28
由于单进程爬虫的种种弊端,以及大量获取数据的需要,我最近开始写分布式爬虫。尽管网上已经有比较现成的方案,如scrapy+rq等,但是出于种种原因考虑,比如部署的难易程度,任务比较单一,以及想自己练练手等,还是决定由自己实现尽可能多的功能。
在写的过程中,不可避免的需要以多线程甚至多进程运行程序。因此解决多线程间以及多进程间的同步和通信问题成为必须。由于进程拥有独立资源,因此多进程同步比多线程同步要更难一些。再加上虽然python中的GIL锁限制了多线程运行的效率,但是由于相关任务比较简单,并不需要太多计算量,因此决定先使用多线程编程。
为了解决这个问题,我先查了查网上的资料,发现似乎所有的解决方案都是基于单个文件的。什么叫基于单个文件呢?就是线程间需要共享的数据都是声明在主文件中的,或者main函数中的
a=1 #需要共享的变量lock=threading.Lock() #锁class test(): def __init__(self): b=2if __name__=='__main__': c=3
举例来说,上面这个文件,经过测试发现a是全局变量。而c似乎也是全局变量,但是我有点不太确定。而b则肯定不是全局变量。网上普遍的解决方案是,在a的位置声明共享变量和lock,这样无论在该文件中什么位置更改变量a,都会造成所有位置中a的值改变。再配合lock,能够解决生产者和消费者问题。但是我发现,当应用场景更复杂一些时,比如需要将这些功能封装在一个类中并且由其他进程来调用这个类时,上述方法不再有效。因为封装类中的变量不再是全局变量
我想了想,目前我能想到的解决方法主要有两个,一个是将变量a声明为全局变量,在子线程中再声明一下global a,这样在该线程的子线程中,任何一个子线程改动a,所有a值都会改变。
__author__ = 'multiangle'import timeimport threadingclass a(): def __init__(self): global data data=5 thread=b() thread.start() self.loop() def loop(self): while True: time.sleep(0.2) print(data)class b(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): while True: time.sleep(0.4) global data data+=1if __name__=='__main__': a()
如上所示,能够得到输出结果为
56677889910...
另外一个方法是将要共享的变量以指针的形式传递给各个子线程,这样所有a都指向同一块内存,自然能够实现变量的同步。由于类对象实例本质也是指针,因此也可以将要共享的变量封装成类在子线程间传递,既实现了内容同步,也保护了要共享的变量。这样有一个潜在的隐患就是所有线程的IO压力都会集中这个类的实例上,可能会造成性能瓶颈,不过目前也不考虑这么多啦。下面上代码
下面这段代码涉及了python的多线程编程,变量共享,还涉及了一些多进程编程。
这段代码总共4个类,
boss,顾名思义,总揽全局,跟踪需要共享变量data的情况,
consum,消费进程
product,生产进程
list_manage , 变量类,核心是要共享的变量pool,还增加了一些外围方法。
lock和data以指针的形式在子线程中传递,观察输出结果可以发现data是在子线程间同步变化的
import threadingimport timefrom multiprocessing import Processclass boss(): def __init__(self): data=list_manage() lock=threading.Lock() self.data=data c0=consume(data,'c0',lock) p=product(data,'p',lock) c1=consume(data,'c1',lock) c0.start() p.start() c1.start() self.go() def go(self): while True: time.sleep(0.1) # print('root process',self.data) # self.data.print() print('boss check , ',self.data.show())class consume(threading.Thread): def __init__(self,data,id,lock): threading.Thread.__init__(self) self.id=id self.data=data self.lock=lock # self.run(data) def run(self): while True : time.sleep(1) self.lock.acquire() print('thread ',self.id,' consume once,get ',self.data.get()) self.lock.release()class product(threading.Thread): def __init__(self,data,id,lock): threading.Thread.__init__(self) self.id=id self.data=data self.lock=lock def run(self): count=0 while True: count+=1 time.sleep(0.4) self.lock.acquire() self.data.add(count) self.lock.release() print('thread ',self.id,' product once, add ',count)class list_manage(): def __init__(self): self.pool=[1,2,3] def get(self): if self.pool.__len__()>0: return self.pool.pop() else: return None def add(self,data): self.pool.append(data) def print(self): print(self.pool) def show(self): copy=self.pool[:] return copyif __name__=='__main__': p=Process(target=boss,args=()) p.start()
以下为输出结果,只截取了最开始的一段
boss check , [1, 2, 3]boss check , [1, 2, 3]boss check , [1, 2, 3]thread p product once, add 1boss check , [1, 2, 3, 1]boss check , [1, 2, 3, 1]boss check , [1, 2, 3, 1]boss check , [1, 2, 3, 1]thread p product once, add 2boss check , [1, 2, 3, 1, 2]boss check , [1, 2, 3, 1, 2]thread c0 consume once,get 2thread c1 consume once,get 1boss check , [1, 2, 3]boss check , [1, 2, 3]thread p product once, add 3boss check , [1, 2, 3, 3]boss check , [1, 2, 3, 3]boss check , [1, 2, 3, 3]boss check , [1, 2, 3, 3]thread p product once, add 4boss check , [1, 2, 3, 3, 4]boss check , [1, 2, 3, 3, 4]boss check , [1, 2, 3, 3, 4]boss check , [1, 2, 3, 3, 4]thread c0 consume once,get 4thread c1 consume once,get 3thread p product once, add 5boss check , [1, 2, 3, 5]boss check , [1, 2, 3, 5]boss check , [1, 2, 3, 5]boss check , [1, 2, 3, 5]thread p product once, add 6boss check , [1, 2, 3, 5, 6]boss check , [1, 2, 3, 5, 6]boss check , [1, 2, 3, 5, 6]
- [Python]多线程编程&线程间共享变量&消费者生产者问题的解决
- Python学习 多线程编程 生产者-消费者问题
- 多线程-生产者消费者问题代码2并解决线程安全问题
- Java多线程编程3--线程间通信--生产者/消费者模式
- 多线程 消费者与生产者 的问题 (线程同步)
- 多线程 生产者消费者模式 线程之间的通讯问题
- 消费者生产者问题---线程互斥锁+条件变量
- Java多线程之生产者消费者问题<二>:使用重入锁、条件变量优雅地解决生产者消费者问题
- C#多线程学习(三) 生产者和消费者 1——解决线程间冲突的关键
- Python--多线程编程--生产者消费者模型
- 互斥锁加条件变量解决生产者消费者问题
- Java多线程解决生产者消费者问题
- NSCondition 多线程解决生产者消费者问题
- 多线程解决生产者与消费者问题
- 使用POSIX线程解决“生产者/消费者”问题
- 用线程解决生产者消费者问题
- 生产者和消费者多线程--线程间通信
- Linux多线程实践(8) --Posix条件变量解决生产者消费者问题
- RxJava教程(二)
- c语言中static用法总结
- 从epoll构建muduo-3 加入第一个类,顺便介绍reactor
- postgreSQL中的case
- linux 最小化安装后配置网络
- [Python]多线程编程&线程间共享变量&消费者生产者问题的解决
- RxJava教程(三)
- WebView的使用
- selenium 整理
- Android内存泄露分析(MAT工具的使用)
- iPhone->类似于popoverView的一个菜单组件
- VS2008 C++ 调用托管C++dll 当前不会命中断点,没有与此关联的代码
- 对xib构建的UITableViewCell的重用方法和代码添加约束的方法 学习笔记
- mysql5.7安装之后的初始化