python多线程并发数量控制

python多线程并发数量控制,第1张

python多线程如果不进行并发数局镇量控制,在启动线程数量多到一定程度后,会造成桐滑粗线程无法启动的错误。

控制多线程并发数量的方法有好几让游钟,下面介绍用queue控制多线程并发数量的方法。python3

进程/多线程+Queue

一般来说,在Python中编写并发程序的经验是:计算密集型任务使用多进程,IO密集型任务使用多进程或者多线程.另外,因为涉及到资源共享,所以需要同步锁等一系列麻悉慎烦的步骤,代码编写不直观.另外一种好的思路是利用多进程/多线程+Queue的方法,可以避免加锁这样麻烦低效的方式.

现在在Python2中利用Queue+多进程的方法来处理一个IO密集型任务.

假设现在需要下载多个网页内容并进行解析,单进程的方式效率很低,所以使用多进程/多线程势在必行.

我们可以先初始化一个tasks队列,里面将要存储的是一系列dest_url,同时开启4个进程向tasks中取任务然后执行,处理结果存储在一个results队列中,最后对results中的结果进行解析.最后关闭两个队列.

下面是一些主要的逻辑代码.

# -*- coding:utf-8 -*-

#IO密集型任务

#多个进程同时下载多个网页

#利用Queue+多进程

#由于是IO密集型,所以同样可以利用threading模块

import multiprocessing

def main():

tasks = multiprocessing.JoinableQueue()

results = multiprocessing.Queue()

cpu_count = multiprocessing.cpu_count() #进程数目==CPU核数目

create_process(tasks, results, cpu_count) #主进程马上创建一系列进程,但是由于阻塞队列tasks开始为空,副进程全部被阻塞

add_tasks(tasks) #开始往tasks中添加任务

parse(tasks, results) #最后主进程等待其他线程处理完成结果

def create_process(tasks, results, cpu_count):

for _ in range(cpu_count):

p = multiprocessing.Process(target=_worker, args=(tasks, results)) #根据_worker创建对应的进程

p.daemon = True #让所有进程可以随主进程结束而结束

p.start() #启动

def _worker(tasks, results):

while True: #因为前面所有线程都散返设置了daemon=True,故不会无限循环

try:

task = tasks.get() #如果tasks中没有任务,则阻塞

result = _download(task)

results.put(result) #some exceptions do not handled

finally:

tasks.task_done()

def add_tasks(tasks):

for url in get_urls(): #get_urls() return a urls_list

tasks.put(url)

def parse(tasks, results):

try:

tasks.join()

except KeyboardInterrupt as err:

print "Tasks has been stopped!"

print err

while not results.empty():

_parse(results)

if __name__ == '__main__':

main()

利冲陆饥用Python3中的concurrent.futures包

在Python3中可以利用concurrent.futures包,编写更加简单易用的多线程/多进程代码.其使用感觉和Java的concurrent框架很相似(借鉴?)

比如下面的简单代码示例

def handler():

futures = set()

with concurrent.futures.ProcessPoolExecutor(max_workers=cpu_count) as executor:

for task in get_task(tasks):

future = executor.submit(task)

futures.add(future)

def wait_for(futures):

try:

for future in concurrent.futures.as_completed(futures):

err = futures.exception()

if not err:

result = future.result()

else:

raise err

except KeyboardInterrupt as e:

for future in futures:

future.cancel()

print "Task has been canceled!"

print e

return result

总结

要是一些大型Python项目也这般编写,那么效率也太低了.在Python中有许多已有的框架使用,使用它们起来更加高效.

但是自己的一些"小打小闹"的程序这样来编写还是不错的.:)

某个时间段内,数据涌来,这就是并发。如果数据量很大,就是高并发

高并发的解决方法:

1、队列、缓冲区

假设只有一个窗口,陆续涌入食堂的人,排队打菜是比较好的方式

所以,排队(队列)是一种天然解决并发的办法

排团游队就是把人排成 队列,先进先出,解决了资源使用的问题

排成的队列,其实就是一个缓冲地带,就是 缓冲区

假设女生优先,每次都从这个队伍中优先选出女生出来先打饭,这就是 优先队列

例如queue模块的类Queue、LifoQueue、PriorityQueue(小顶堆实现)

2、争抢

只开一个窗口,有可能没有秩序,举或猛也就是谁挤进去就给谁打饭

挤到窗口的人占据窗口,直到打到饭菜离开

其他人继续争抢,会有一个人占据着窗口,可以视为锁定窗口,窗口就不能为其他人提供服务了。

这是一种锁机制

谁抢到资源就上锁,排他性的锁,其他人只能等候

争抢也是一种高并发解决方案,但是,这样可能不好,因为有可能有人很长时间抢不到

3、预处理

如果排长队的原因,是由于每个人打菜等候时间长,因为要吃的菜没有,需要现做,没打着饭不走开,锁定着窗口

食堂可以提前统计大多数人最爱吃的菜品,将最爱吃的80%的热门菜,提前做好,保证供应,20%的冷门菜,现做

这样大多数人,就算锁定窗口,也很快打到饭菜走了,快速释放窗口

一种提前加载用户需要的数据的思路,预处理 思想正桥,缓存常用

更多Python知识,请关注:Python自学网!!


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12340911.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存