python用例并发怎么解决

python用例并发怎么解决,第1张

python-selenium并发执行测试用例(方法一 各模块每一条并发执行)

总执行代码:

# coding=utf-8

import unittest,os,time

import HTMLTestRunner

import threading

import sys

syspathappend('C:/Users/Dell/Desktop/CARE/program')#使用编辑器,要指定当前目录,不然无法执行第20行代码

def creatsuite():

casedir = []

list = oslistdir(ospathdirname(osgetcwd()))#获取当前路径的上一级目录的所有文件夹,这里可以改成绝对路径(要搜索的文件路径)

for xx in list:

if "baidu" in xx:

casedirappend(xx)

suite =[]

for n in casedir:

testunit = unittestTestSuite()

unittestdefaultTestLoader_top_level_dir = None

#(unittestdefaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动更具测试目录start_dir匹配查找测试用例文件(testpy),

并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover)

discover = unittestdefaultTestLoaderdiscover(str(n),pattern='tet_py',top_level_dir=None)

for test_suite in discover:

for test_case in test_suite:

testunitaddTests(test_case)

suiteappend(testunit)

return suite, casedir

def runcase(suite,casedir):

lastPath = ospathdirname(osgetcwd())#获取当前路径的上一级

resultDir = lastPath+"\\run\\report\\" #报告存放路径

now = timestrftime("%Y-%m-%d %H%M%S",timelocaltime())

filename = resultDir + now +" resulthtml"

fp = file(filename, 'wb')

proclist=[]

s=0

for i in suite:

runner = HTMLTestRunnerHTMLTestRunner(stream=fp,title=str(casedir[s])+u'测试报告',description=u'用例执行情况:')

proc = threadingThread(target=runnerrun,args=(i,))

proclistappend(proc)

s=s+1

for proc in proclist:

procstart()

for proc in proclist:

procjoin()

fpclose()

if __name__ == "__main__":

runtmp=creatsuite()

runcase(runtmp[0],runtmp[1])

线程高并发不容易。因为python的线程虽然是真线程,不过它有GIL。 所以通常会使用twisted工具,高并发就不是难题了。在linux下更容易。

由于windows下不知道socket的复制。所以不能使用多进程管理多个python实例处理一个端口的请求。

所以建议你走另外一条路,使用nginx之类的代理,再通过wsgi连接。

另外一种办法是使用jython, 这是没有GIL锁的。

不过话说回来,高并发并不取决于语言快慢。而在于处理请求的快慢。 如果你的请求处理速度极快,即使10个线程也可以高并发到3000以上。甚至8000都可以做到。

第一个就是并发本身所带来的开销即新开处理线程、关闭处理线程、多个处理线程时间片轮转所带来的开销。

实际上对于一些逻辑不那么复杂的场景来说这些开销甚至比真正的处理逻辑部分代码的开销更大。所以我们决定采用基于协程的并发方式,即服务进程只有一个(单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上写入一份冗余数据,当读取原始数据失败时可以立即尝试读取冗余数据而不会造成服务中断。

1 介绍

11 为什么要使用Stackless

摘自 stackless 网站。

Note

Stackless Python 是Python编程语言的一个增强版本,它使程序员从基于线程的编程方式中获得好处,并避免传统线程所带来的性能与复杂度问题。Stackless为 Python带来的微线程扩展,是一种低开销、轻量级的便利工具,如果使用得当,可以获益如下:

改进程序结构

增进代码可读性

提高编程人员生产力

以上是Stackless Python很简明的释义,但其对我们意义何在?——就在于Stackless提供的并发建模工具,比目前其它大多数传统编程语言所提供的,都更加易用: 不仅是Python自身,也包括Java、C++,以及其它。尽管还有其他一些语言提供并发特性,可它们要么是主要用于学术研究的(如 Mozart/Oz),要么是罕为使用、或用于特殊目的的专业语言(如Erlang)。而使用stackless,你将会在Python本身的所有优势之 上,在一个(但愿)你已经很熟悉的环境中,再获得并发的特性。

这自然引出了个问题:为什么要并发?

111 现实世界就是并发的

现实世界就是“并发”的,它是由一群事物(或“演员”)所组成,而这些事物以一种对彼此所知有限的、松散耦合的方式相互作用。传说中面向对象编程有 一个好处,就是对象能够对现实的世界进行模拟。这在一定程度上是正确的,面向对象编程很好地模拟了对象个体,但对于这些对象个体之间的交互,却无法以一种 理想的方式来表现。例如,如下代码实例,有什么问题?

def familyTacoNight():

   husbandeat(dinner)

   wifeeat(dinner)

   soneat(dinner)

   daughtereat(dinner)

第一印象,没问题。但是,上例中存在一个微妙的安排:所有事件是次序发生的,即:直到丈夫吃完饭,妻子才开始吃;儿子则一直等到母亲吃完才吃;而女 儿则是最后一个。在现实世界中,哪怕是丈夫还堵车在路上,妻子、儿子和女儿仍然可以该吃就吃,而要在上例中的话,他们只能饿死了——甚至更糟:永远没有人 会知道这件事,因为他们永远不会有机会抛出一个异常来通知这个世界!

112 并发可能是(仅仅可能是)下一个重要的编程范式

我个人相信,并发将是软件世界里的下一个重要范式。随着程序变得更加复杂和耗费资源,我们已经不能指望摩尔定律来每年给我们提供更快的CPU了,当 前,日常使用的个人计算机的性能提升来自于多核与多CPU机。一旦单个CPU的性能达到极限,软件开发者们将不得不转向分布式模型,靠多台计算机的互相协 作来建立强大的应用(想想GooglePlex)。为了取得多核机和分布式编程的优势,并发将很快成为做事情的方式的事实标准。

12 安装stackless

安装Stackless的细节可以在其网站上找到。现在Linux用户可以通过SubVersion取得源代码并编译;而对于Windows用户, 则有一个zip文件供使用,需要将其解压到现有的Python安装目录中。接下来,本教程假设Stackless Python已经安装好了,可以工作,并且假设你对Python语言本身有基本的了解。

2 stackless起步

本章简要介绍了 stackless 的基本概念,后面章节将基于这些基础,来展示更加实用的功能。

21 微进程(tasklet)

微进程是stackless的基本构成单元,你可以通过提供任一个Python可调用对象(通常为函数或类的方法)来建立它,这将建立一个微进程并将其添加到调度器。这是一个快速演示:

Python 243 Stackless 31b3 060504 (#69, May  3 2006, 19:20:41) [MSC v1310 32

bit (Intel)] on win32

Type "help", "copyright", "credits" or "license" for more information

>>> import stackless

>>>

>>> def print_x(x):

    print x

>>> stacklesstasklet(print_x)('one')

<stacklesstasklet object at 0x00A45870>

>>> stacklesstasklet(print_x)('two')

<stacklesstasklet object at 0x00A45A30>

>>> stacklesstasklet(print_x)('three')

<stacklesstasklet object at 0x00A45AB0>

>>>

>>> stacklessrun()

one

two

three

>>>

注意,微进程将排起队来,并不运行,直到调用 stacklessrun() 。

22 调度器(scheduler)

调度器控制各个微进程运行的顺序。如果刚刚建立了一组微进程,它们将按照建立的顺序来执行。在现实中,一般会建立一组可以再次被调度的微进程,好让每个都有轮次机会。一个快速演示:

Python 243 Stackless 31b3 060504 (#69, May  3 2006, 19:20:41) [MSC v1310 32

bit (Intel)] on win32

Type "help", "copyright", "credits" or "license" for more information

>>> import stackless

>>>

>>> def print_three_times(x):

    print "1:", x

    stacklessschedule()

    print "2:", x

    stacklessschedule()

    print "3:", x

    stacklessschedule()

>>>

>>> stacklesstasklet(print_three_times)('first')

<stacklesstasklet object at 0x00A45870>

>>> stacklesstasklet(print_three_times)('second')

<stacklesstasklet object at 0x00A45A30>

>>> stacklesstasklet(print_three_times)('third')

<stacklesstasklet object at 0x00A45AB0>

>>>

>>> stacklessrun()

1: first

1: second

1: third

2: first

2: second

2: third

3: first

3: second

3: third

>>>

注意:当调用 stacklessschedule() 的时候,当前活动微进程将暂停执行,并将自身重新插入到调度器队列的末尾,好让下一个微进程被执行。一旦在它前面的所有其他微进程都运行过了,它将从上次 停止的地方继续开始运行。这个过程会持续,直到所有的活动微进程都完成了运行过程。这就是使用stackless达到合作式多任务的方式。

23 通道(channel)

通道使得微进程之间的信息传递成为可能。它做到了两件事:

能够在微进程之间交换信息。

能够控制运行的流程。

又一个快速演示:

C:>c:python24python

Python 243 Stackless 31b3 060504 (#69, May  3 2006, 19:20:41) [MSC v1310 32

bit (Intel)] on win32

Type "help", "copyright", "credits" or "license" for more information

>>> import stackless

>>>

>>> channel = stacklesschannel()

>>>

>>> def receiving_tasklet():

    print "Recieving tasklet started"

    print channelreceive()

    print "Receiving tasklet finished"

>>> def sending_tasklet():

    print "Sending tasklet started"

    channelsend("send from sending_tasklet")

    print "sending tasklet finished"

>>> def another_tasklet():

    print "Just another tasklet in the scheduler"

>>> stacklesstasklet(receiving_tasklet)()

<stacklesstasklet object at 0x00A45B30>

>>> stacklesstasklet(sending_tasklet)()

<stacklesstasklet object at 0x00A45B70>

>>> stacklesstasklet(another_tasklet)()

<stacklesstasklet object at 0x00A45BF0>

>>>

>>> stacklessrun()

Recieving tasklet started

Sending tasklet started

send from sending_tasklet

Receiving tasklet finished

Just another tasklet in the scheduler

sending tasklet finished

>>>

接收的微进程调用 channelreceive() 的时候,便阻塞住,这意味着该微进程暂停执行,直到有信息从这个通道送过来。除了往这个通道发送信息以外,没有其他任何方式可以让这个微进程恢复运行。

若有其他微进程向这个通道发送了信息,则不管当前的调度到了哪里,这个接收的微进程都立即恢复执行;而发送信息的微进程则被转移到调度列表的末尾,就像调用了 stacklessschedule() 一样。

同样注意,发送信息的时候,若当时没有微进程正在这个通道上接收,也会使当前微进程阻塞:

>>> stacklesstasklet(sending_tasklet)()

<stacklesstasklet object at 0x00A45B70>

>>> stacklesstasklet(another_tasklet)()

<stacklesstasklet object at 0x00A45BF0>

>>>

>>> stacklessrun()

Sending tasklet started

Just another tasklet in the scheduler

>>>

>>> stacklesstasklet(another_tasklet)()

<stacklesstasklet object at 0x00A45B30>

>>> stacklessrun()

Just another tasklet in the scheduler

>>>

>>> #Finally adding the receiving tasklet

>>> stacklesstasklet(receiving_tasklet)()

<stacklesstasklet object at 0x00A45BF0>

>>>

>>> stacklessrun()

Recieving tasklet started

send from sending_tasklet

Receiving tasklet finished

sending tasklet finished

发送信息的微进程,只有在成功地将数据发送到了另一个微进程之后,才会重新被插入到调度器中。

24 总结

以上涵盖了stackless的大部分功能。似乎不多是吧?——我们只使用了少许对象,和大约四五个函数调用,来进行 *** 作。但是,使用这种简单的API作为基本建造单元,我们可以开始做一些真正有趣的事情。

3 协程(coroutine)

31 子例程的问题

大多数传统编程语言具有子例程的概念。一个子例程被另一个例程(可能还是其它某个例程的子例程)所调用,或返回一个结果,或不返回结果。从定义上说,一个子例程是从属于其调用者的。

见下例:

def ping():

   print "PING"

   pong()

def pong():

   print "PONG"

   ping()

ping()

有经验的编程者会看到这个程序的问题所在:它导致了堆栈溢出。如果运行这个程序,它将显示一大堆讨厌的跟踪信息,来指出堆栈空间已经耗尽。

311 堆栈

我仔细考虑了,自己对C语言堆栈的细节究竟了解多少,最终还是决定完全不去讲它。似乎,其他人对其所尝试的描述,以及图表,只有本身已经理解了的人才能看得懂。我将试着给出一个最简单的说明,而对其有更多兴趣的读者可以从网上查找更多信息。

每当一个子例程被调用,都有一个“栈帧”被建立,这是用来保存变量,以及其他子例程局部信息的区域。于是,当你调用 ping() ,则有一个栈帧被建立,来保存这次调用相关的信息。简言之,这个帧记载着 ping 被调用了。当再调用 pong() ,则又建立了一个栈帧,记载着 pong 也被调用了。这些栈帧是串联在一起的,每个子例程调用都是其中的一环。就这样,堆栈中显示: ping 被调用所以 pong 接下来被调用。显然,当 pong() 再调用 ping() ,则使堆栈再扩展。下面是个直观的表示:

帧    堆栈  

1    ping 被调用  

2    ping 被调用,所以 pong 被调用  

3    ping 被调用,所以 pong 被调用,所以 ping 被调用  

4    ping 被调用,所以 pong 被调用,所以 ping 被调用,所以 pong 被调用  

5    ping 被调用,所以 pong 被调用,所以 ping 被调用,所以 pong 被调用,所以 ping 被调用  

6    ping 被调用,所以 pong 被调用,所以 ping 被调用,所以 pong 被调用,所以 ping 被调用……  

现在假设,这个页面的宽度就表示系统为堆栈所分配的全部内存空间,当其顶到页面的边缘的时候,将会发生溢出,系统内存耗尽,即术语“堆栈溢出”。

312 那么,为什么要使用堆栈?

上例是有意设计的,用来体现堆栈的问题所在。在大多数情况下,当每个子例程返回的时候,其栈帧将被清除掉,就是说堆栈将会自行实现清理过程。这一般 来说是件好事,在C语言中,堆栈就是一个不需要编程者来手动进行内存管理的区域。很幸运,Python程序员也不需要直接来担心内存管理与堆栈。但是由于 Python解释器本身也是用C实现的,那些实现者们可是需要担心这个的。使用堆栈是会使事情方便,除非我们开始调用那种从不返回的函数,如上例中的,那 时候,堆栈的表现就开始和程序员别扭起来,并耗尽可用的内存。

32 走进协程

此时,将堆栈弄溢出是有点愚蠢的。 ping() 和 pong() 本不是真正意义的子例程,因为其中哪个也不从属于另一个,它们是“协程”,处于同等的地位,并可以彼此间进行无缝通信。

帧    堆栈  

1    ping 被调用  

2    pong 被调用  

3    ping 被调用  

4    pong 被调用  

5    ping 被调用  

6    pong 被调用  

在stackless中,我们使用通道来建立协程。还记得吗,通道所带来的两个好处中的一个,就是能够控制微进程之间运行的流程。使用通道,我们可以在 ping 和 pong 这两个协程之间自由来回,要多少次就多少次,都不会堆栈溢出:

#

# pingpong_stacklesspy

#

import stackless

ping_channel = stacklesschannel()

pong_channel = stacklesschannel()

def ping():

   while ping_channelreceive(): #在此阻塞

       print "PING"

       pong_channelsend("from ping")

def pong():

   while pong_channelreceive():

       print "PONG"

       ping_channelsend("from pong")

stacklesstasklet(ping)()

stacklesstasklet(pong)()

# 我们需要发送一个消息来初始化这个游戏的状态

# 否则,两个微进程都会阻塞

stacklesstasklet(ping_channelsend)('startup')

stacklessrun()

你可以运行这个程序要多久有多久,它都不会崩溃,且如果你检查其内存使用量(使用Windows的任务管理器或Linux的top命令),将会发现 使用量是恒定的。这个程序的协程版本,不管运行一分钟还是一天,使用的内存都是一样的。而如果你检查原先那个递归版本的内存用量,则会发现其迅速增长,直 到崩溃。

33 总结

是否还记得,先前我提到过,那个代码的递归版本,有经验的程序员会一眼看出毛病。但老实说,这里面并没有什么“计算机科学”方面的原因在阻碍它的正 常工作,有些让人坚信的东西,其实只是个与实现细节有关的小问题——只因为大多数传统编程语言都使用堆栈。某种意义上说,有经验的程序员都是被洗了脑,从 而相信这是个可以接受的问题。而stackless,则真正察觉了这个问题,并除掉了它。

4 轻量级线程

与当今的 *** 作系统中内建的、和标准Python代码中所支持的普通线程相比,“微线程”要更为轻量级,正如其名称所暗示。它比传统线程占用更少的内存,并且微线程之间的切换,要比传统线程之间的切换更加节省资源。

为了准确说明微线程的效率究竟比传统线程高多少,我们用两者来写同一个程序。

41 hackysack模拟

Hackysack是一种游戏,就是一伙脏乎乎的小子围成一个圈,来回踢一个装满了豆粒的沙包,目标是不让这个沙包落地,当传球给别人的时候,可以耍各种把戏。踢沙包只可以用脚。

在我们的简易模拟中,我们假设一旦游戏开始,圈里人数就是恒定的,并且每个人都是如此厉害,以至于如果允许的话,这个游戏可以永远停不下来。

42 游戏的传统线程版本

import thread

import random

import sys

import Queue

class hackysacker:

   counter = 0

   def __init__(self,name,circle):

       selfname = name

       selfcircle = circle

       circleappend(self)

       selfmessageQueue = QueueQueue()

       threadstart_new_thread(selfmessageLoop,())

   def incrementCounter(self):

       hackysackercounter += 1

       if hackysackercounter >= turns:

           while selfcircle:

               hs = selfcirclepop()

               if hs is not self:

                   hsmessageQueueput('exit')

           sysexit()

   def messageLoop(self):

       while 1:

           message = selfmessageQueueget()

           if message == "exit":

               debugPrint("%s is going home" % selfname)

               sysexit()

           debugPrint("%s got hackeysack from %s" % (selfname, messagename))

           kickTo = selfcircle[randomrandint(0,len(selfcircle)-1)]

           debugPrint("%s kicking hackeysack to %s" % (selfname, kickToname))

           selfincrementCounter()

           kickTomessageQueueput(self)

def debugPrint(x):

   if debug:

       print x

debug=1

hackysackers=5

turns = 5

Django: Py Web应用开发框架

Diesel:基于Greenlet的事件I/O框架

Flask:一个用Py编写的轻量级Web应用框架

Cubes:轻量级Py OLAP框架

Kartographpy:创造矢量地图的轻量级Py框架

Pulsar:Py的事件驱动并发框架

Web2py:全栈式Web框架

Falcon:构建云API和网络应用后端的高性能Py框架

Dpark:Py版的Spark

Buildbot:基于Py的持续集成测试框架

Zerorpc:基于ZeroMQ的高性能分布式RPC框架

Bottle: 微型Py Web框架

Tornado:异步非阻塞IO的Py Web框架

webpy: 轻量级的Py Web框架

Scrapy:Py的爬虫框架

希望楼主~~。

以上就是关于python用例并发怎么解决全部的内容,包括:python用例并发怎么解决、求大神 帮忙 在 windos 下写 python socket 服务器。多线程高并发的,3000以上。python2.7 的环境。、如何用Python一门语言通吃高性能并发,GPU计算和深度学习等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

原文地址: http://outofmemory.cn/zz/10107647.html

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

发表评论

登录后才能评论

评论列表(0条)

保存