Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/firebase/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 负载测试脚本的线程或多处理_Python_Pyodbc - Fatal编程技术网

Python 负载测试脚本的线程或多处理

Python 负载测试脚本的线程或多处理,python,pyodbc,Python,Pyodbc,我编写了一些代码,用于在用户同时对数据库运行查询时测试数据库的性能。目的是了解运行时间是如何随着用户数量的增加而增加的。代码包含一个类User(如下所示),其对象是通过解析XML文件创建的 class User(object): def __init__(self, id, constr): self.id = id self.constr = constr self.queryid = list() self.queri

我编写了一些代码,用于在用户同时对数据库运行查询时测试数据库的性能。目的是了解运行时间是如何随着用户数量的增加而增加的。代码包含一个类User(如下所示),其对象是通过解析XML文件创建的

class User(object):

    def __init__(self, id, constr):
        self.id = id
        self.constr = constr
        self.queryid = list()
        self.queries = list()

    def openConn(self):
        self.cnxn = pyodbc.connect(self.constr)
        logDet.info("%s %s"%(self.id,"Open connection."))

    def closeConn(self):
        self.cnxn.close()
        logDet.info("%s %s"%(self.id,"Close connection."))

    def executeAll(self):
        self.openConn()

        for n,qry in enumerate(self.queries):
            try:
                cursor = self.cnxn.cursor()
                logTim.info("%s|%s|beg"%(self.id, self.queryid[n]))
                cursor.execute(qry)
                logTim.info("%s|%s|end"%(self.id, self.queryid[n]))

            except Exception:
                cursor.rollback()
                logDet.exception("Error while running query.")

        self.closeConn()
pyODBC用于连接到数据库。创建了两个日志——一个详细日志(logDet)和一个只有计时的日志(logTim)。用户对象存储在列表中。每个用户的查询也在列表中(不在线程安全队列中)

为了模拟并行用户,我尝试了两种不同的方法:

def worker(usr):
    usr.executeAll()
选项1:多处理池

pool = Pool(processes=len(users))
pool.map(worker, users)
选项2:线程。线程

for usr in users:
    t = Thread(target=worker, args=(usr,))
    t.start()
这两种方法都有效。在我的测试中,我尝试了#users=2,6,…,60,每个用户有4个查询。考虑到如何捕获查询时间,在查询结束和下一个查询开始之间应有不到一秒的延迟,即应一个接一个地触发查询。这正是多处理的情况,但对于线程,在下一次查询之前会引入随机延迟。延迟可能超过一分钟(见下文)

使用:python3.4.1、pyodbc3.0.7;运行代码为Windows 7/RHEL 6.5的客户端


我真的更愿意让它与线程一起工作。这是线程方法中所期望的,还是缺少一个命令?或者怎样才能重新书写?Thx.

当您使用基于
线程的方法时,您将为每个用户启动一个线程,最多60个线程。所有这些线程都必须在I/O操作之间争取对GIL的访问。这介绍了。如果使用的
ThreadPool
仅限于少量线程(可能是
2*多处理.cpu\u count()
?),即使用户数量较高,也可能会看到更好的结果:

from multiprocessing.pool import ThreadPool
from multiprocessing import cpu_count

pool = ThreadPool(processes=cpu_count()*2)
pool.map(worker, users)

出于内存使用的原因,您可能也想限制运行的并发进程的数量。启动60个并发Python进程非常昂贵。

谢谢@dano。我对你的评论有点困惑,“你可能也想限制你运行的并发进程的数量”。如果我使用您的线程池想法,我不需要这样做,是吗?@ironv如果您使用
线程池
,则不需要。但是如果您选择使用常规的
多处理.Pool
,您可能希望使用少于
len(用户)
的进程来减少内存开销。对于这么多的进程,您可能对CPU的负担也比您真正想要的要大。我观察到的另一种情况甚至是它的原始形式(从我的OP中),线程解决方案在Windows上运行良好,而多处理。池解决方案在RHEL上运行良好。在您发布之前,我正在对“nt”或“posix”进行os.name检查,并且正在调用其中一个。我现在正在Windows上测试线程池,然后在Linux上尝试,看看是否有延迟。另一个问题是我的RHEL盒有96个核心。我还应该使用cpu_count()*2吗?或者做一个最小值(SOMELIMIT,cpu_count()*2)?96个内核?!我嫉妒。有这么多内核,在基于进程池的方法中,我担心
2*cpu\u count()
会使内存负担过重。您的最大用户数为60个,因此无论如何,您将不会使用超过60个进程。你可能会做得很好,甚至更少。确实很难说什么数字对你来说是最合适的,这是一种你只能通过测试不同值来验证的东西。阅读了你之前提到的Beazley演示,我有一个问题。在我的脚本中,线程所做的唯一工作是(i)使用pyODBC抓取并启动一个查询,然后等待它完成(ii)将结束时间写入日志文件。重复一遍。问题:是在线程等待查询完成时释放GIL,还是在查询完成后才释放GIL?