Ⅰ 如何在python中编写并发程序
多进程/多线程+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中有许多已有的框架使用,使用它们起来更加高效.
但是自己的一些"小打小闹"的程序这样来编写还是不错的.:)
Ⅱ Python几种并发实现方案的性能比较
1.目前推荐使用gevent吧,当然,结合起python的jit技术实现,可突破gil的限制,pypy还是可观的,内存上可能比cpython占用大些
Ⅲ python用例并发怎么解决
python-selenium并发执行测试用例(方法一 各模块每一条并发执行)
总执行代码:
# coding=utf-8
import unittest,os,time
import HTMLTestRunner
import threading
import sys
sys.path.append('C:/Users/Dell/Desktop/CARE/program')#使用编辑器,要指定当前目录,不然无法执行第20行代码
def creatsuite():
casedir = []
list = os.listdir(os.path.dirname(os.getcwd()))#获取当前路径的上一级目录的所有文件夹,这里可以改成绝对路径(要搜索的文件路径)
for xx in list:
if "" in xx:
casedir.append(xx)
suite =[]
for n in casedir:
testunit = unittest.TestSuite()
unittest.defaultTestLoader._top_level_dir = None
#(unittest.defaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动更具测试目录start_dir匹配查找测试用例文件(test*.py),
并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover)
discover = unittest.defaultTestLoader.discover(str(n),pattern='tet_*.py',top_level_dir=None)
for test_suite in discover:
for test_case in test_suite:
testunit.addTests(test_case)
suite.append(testunit)
return suite, casedir
def runcase(suite,casedir):
lastPath = os.path.dirname(os.getcwd())#获取当前路径的上一级
resultDir = lastPath+"\\run\\report\\" #报告存放路径
now = time.strftime("%Y-%m-%d %H.%M.%S",time.localtime())
filename = resultDir + now +" result.html"
fp = file(filename, 'wb')
proclist=[]
s=0
for i in suite:
runner = HTMLTestRunner.HTMLTestRunner(stream=fp,title=str(casedir[s])+u'测试报告',description=u'用例执行情况:')
proc = threading.Thread(target=runner.run,args=(i,))
proclist.append(proc)
s=s+1
for proc in proclist:
proc.start()
for proc in proclist:
proc.join()
fp.close()
if __name__ == "__main__":
runtmp=creatsuite()
runcase(runtmp[0],runtmp[1])
Ⅳ 有没有人写过python的一秒3000个并发请求的服务端
有个国产的web框架:eurasia, 业界大牛 沈老大 写的,貌似用了stackless python
自己写了一个tcp的server,epoll based,测过并发60k,不是web框架,没测过每秒请求数。
python搭tcp/web server都很快,现成的web框架多,裸tcp的框架少
Ⅳ 如何用Python一门语言通吃高性能并发,GPU计算和深度学习
第一个就是并发本身所带来的开销即新开处理线程、关闭处理线程、多个处理线程时间片轮转所带来的开销。
实际上对于一些逻辑不那么复杂的场景来说这些开销甚至比真正的处理逻辑部分代码的开销更大。所以我们决定采用基于协程的并发方式,即服务进程只有一个(单cpu)所有的请求数据都由这个服务进程内部来维护,同时服务进程自行调度不同请求的处理顺序,这样避免了传统多线程并发方式新建、销毁以及系统调度处理线程的开销。基于这样的考虑我们选择了基于Tornado框架实现api服务的开发。Tornado的实现非常简洁明了,使用python的生成器作为协程,利用IOLoop实现了调度队列。
第二个问题是数据库的性能,这里说的数据库包括MongoDB和Redis,我这里分开讲。
先讲MongoDB的问题,MongoDB主要存储不同的用户对于验证的不同设置,比如该显示什么样的图片。
一开始每次验证请求都会查询MongoDB,当时我们的MongoDB是纯内存的,同时三台机器组成一个复制集,这样的组合大概能稳定承载八九千的qps,后来随着我们验证量越来越大,这个承载能力逐渐就成为了我们的瓶颈。
为了彻底搞定这个问题,我们提出了最极端的解决方案,干脆直接把数据库中的数据完全缓存到服务进程里定期批量更新,这样查询的开销将大大降低。但是因为我们用的是Python,由于GIL的存在,在8核服务器上会fork出来8个服务进程,进程之间不像线程那么方便,所以我们基于mmap自己写了一套伙伴算法构建了一个跨进程共享缓存。自从这套缓存上线之后,Mongodb的负载几乎变成了零。
说完了MongoDB再说Redis的问题,Redis代码简洁、数据结构丰富、性能强大,唯一的问题是作为一个单进程程序,终究性能是有上限的。
虽然今年Redis发布了官方的集群版本,但是经过我们的测试,认为这套分布式方案的故障恢复时间不够优秀并且运维成本较高。在Redis官方集群方案面世之前,开源世界有不少proxy方案,比如Twtter的TwemProxy和豌豆荚的Codis。这两种方案测试完之后给我们的感觉TwemProxy运维还是比较麻烦,Codis使用起来让人非常心旷神怡,无论是修改配置还是扩容都可以在配置页面上完成,并且性能也还算不错,但无奈当时Codis还有比较严重的BUG只能放弃之。
几乎尝试过各种方案之后,我们还是下决心自己实现一套分布式方案,目的是高度贴合我们的需求并且运维成本要低、扩容要方便、故障切换要快最重要的是数据冗余一定要做好。
基于上面的考虑,我们确定基于客户端的分布式方案,通过zookeeper来同步状态保证高可用。具体来说,我们修改Redis源码,使其向zookeeper注册,客户端由zookeeper上获取Redis服务器集群信息并根据统一的一致性哈希算法来计算数据应该存储在哪台Redis上,并在哈希环的下一台Redis上写入一份冗余数据,当读取原始数据失败时可以立即尝试读取冗余数据而不会造成服务中断。
Ⅵ 高并发,用Python适合吗
Python不太适合高并发,虽然可以做,但是问题还是比较大,特别如果是后端服务,需要很高的高并发的话,还是用其他语言。
要高并发的话, 多进程+协程的组合的并发性能远高于多线程。我在这篇文章中对python的并发方案有过比较。 像是要发各种请求的,其实和爬虫类似, 协程的方案比较合适,能达到很高的并发。
Python简介:
Python由荷兰数学和计算机科学研究学会的Guido van Rossum于1990 年代初设计,作为一门叫做ABC语言的替代品。
Python提供了高效的高级数据结构,还能简单有效地面向对象编程。Python语法和动态类型,以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的编程语言,随着版本的不断更新和语言新功能的添加,逐渐被用于独立的、大型项目的开发。
Ⅶ python现在做高并发服务器 性能怎么样
你要相信一点,现在服务器的瓶颈主要不在语言,而是磁盘IO,网络IO,业务逻辑等等。
对于几乎所有现代语言,对C10K问题都能比较好的解决。
HTTP/2、异步、协程、RESTful等等技术都在一定程度帮我们处理C10K问题,Python世界也有很多开源库帮我们解决这些问题(换成Java也差不多)。
我公司目前使用的方案有:使用Nginx支持HTTP/2,实现简单负载均衡,使用Python Tornado + RabbitMQ异步处理耗时任务,但应用主体还是基于Python FlaskRESTful。
也许使用Java或Go可以提升性能,但我们看中的是Python的工程型、可读性、可维护性,适合快速迭代开发。
Ⅷ python高并发怎么解决
某个时间段内,数据涌来,这就是并发。如果数据量很大,就是高并发
高并发的解决方法:
1、队列、缓冲区
假设只有一个窗口,陆续涌入食堂的人,排队打菜是比较好的方式
所以,排队(队列)是一种天然解决并发的办法
排队就是把人排成 队列,先进先出,解决了资源使用的问题
排成的队列,其实就是一个缓冲地带,就是 缓冲区
假设女生优先,每次都从这个队伍中优先选出女生出来先打饭,这就是 优先队列
例如queue模块的类Queue、LifoQueue、PriorityQueue(小顶堆实现)
2、争抢
只开一个窗口,有可能没有秩序,也就是谁挤进去就给谁打饭
挤到窗口的人占据窗口,直到打到饭菜离开
其他人继续争抢,会有一个人占据着窗口,可以视为锁定窗口,窗口就不能为其他人提供服务了。
这是一种锁机制
谁抢到资源就上锁,排他性的锁,其他人只能等候
争抢也是一种高并发解决方案,但是,这样可能不好,因为有可能有人很长时间抢不到
3、预处理
如果排长队的原因,是由于每个人打菜等候时间长,因为要吃的菜没有,需要现做,没打着饭不走开,锁定着窗口
食堂可以提前统计大多数人最爱吃的菜品,将最爱吃的80%的热门菜,提前做好,保证供应,20%的冷门菜,现做
这样大多数人,就算锁定窗口,也很快打到饭菜走了,快速释放窗口
一种提前加载用户需要的数据的思路,预处理 思想,缓存常用
更多Python知识,请关注:Python自学网!!
Ⅸ 如何使用Python实现并发编程
多线程几乎是每一个程序猿在使用每一种语言时都会首先想到用于解决并发的工具(JS程序员请回避),使用多线程可以有效的利用CPU资源(Python例外)。然而多线程所带来的程序的复杂度也不可避免,尤其是对竞争资源的同步问题。
然而在python中由于使用了全局解释锁(GIL)的原因,代码并不能同时在多核上并发的运行,也就是说,Python的多线程不能并发,很多人会发现使用多线程来改进自己的Python代码后,程序的运行效率却下降了,这是多么蛋疼的一件事呀!如果想了解更多细节,推荐阅读这篇文章。实际上使用多线程的编程模型是很困难的,程序员很容易犯错,这并不是程序员的错误,因为并行思维是反人类的,我们大多数人的思维是串行(精神分裂不讨论),而且冯诺依曼设计的计算机架构也是以顺序执行为基础的。所以如果你总是不能把你的多线程程序搞定,恭喜你,你是个思维正常的程序猿:)
Python提供两组线程的接口,一组是thread模块,提供基础的,低等级(Low Level)接口,使用Function作为线程的运行体。还有一组是threading模块,提供更容易使用的基于对象的接口(类似于Java),可以继承Thread对象来实现线程,还提供了其它一些线程相关的对象,例如Timer,Lock
使用thread模块的例子
import thread
def worker():
"""thread worker function"""
print 'Worker'
thread.start_new_thread(worker)
使用threading模块的例子
import threading
def worker():
"""thread worker function"""
print 'Worker'
t = threading.Thread(target=worker)
t.start()
或者Java Style
import threading
class worker(threading.Thread):
def __init__(self):
pass
def run():
"""thread worker function"""
print 'Worker'
t = worker()
t.start()