多次并行执行时,Python脚本执行时间会增加

时间:2016-08-29 11:17:07

标签: python time

我有一个python脚本,执行时间是1.2秒,而它是独立执行的。

但是当我平行执行5-6次时(我使用邮差多次ping网址),执行时间就会开始。

添加所用时间的细分。

import psutil
import os
import time
start_time = time.time()
import cgitb
cgitb.enable()
import numpy as np
import MySQLdb as mysql
import cv2
import sys
import rpy2.robjects as robj
import rpy2.robjects.numpy2ri
rpy2.robjects.numpy2ri.activate()
from rpy2.robjects.packages import importr
R = robj.r
DTW = importr('dtw')

process= psutil.Process(os.getpid())
print " Memory Consumed after libraries load: "
print process.memory_info()[0]/float(2**20)

st_pt=4
# Generate our data (numpy arrays)
template = np.array([range(84),range(84),range(84)]).transpose()
query = np.array([range(2500000),range(2500000),range(2500000)]).transpose()


#time taken
print(" --- %s seconds ---" % (time.time() - start_time))

top命令的屏幕截图(在评论中提问): enter image description here

这是一个示例代码:

watch -n 1 free -m

我还使用#!/home/ec2-user/anaconda/envs/test_python/检查了我的内存消耗,内存消耗也明显增加。

1)如何确保每次脚本的执行时间保持不变。

2)我可以永久加载库,以便脚本加载库所花费的时间和消耗的内存可以最小化吗?

我做了一个环境并尝试使用

<?php $response = array("error" => FALSE); if($_SERVER['REQUEST_METHOD']=='GET'){ $response["error"] = FALSE; $command =escapeshellcmd(shell_exec("sudo /home/ec2-user/anaconda/envs/anubhaw_python/bin/python2.7 /var/www/cgi-bin/dtw_test_code.py")); session_write_close(); $order=array("\n","\\"); $cleanData=str_replace($order,'',$command); $response["message"]=$cleanData; } else { header('HTTP/1.0 400 Bad Request'); $response["message"] = "Bad Request."; } echo json_encode($response); ?>

但它没有任何区别。

修改

我有AMAZON的EC2服务器,内存为7.5GB。

我正在调用python脚本的php文件。

IDE

由于

5 个答案:

答案 0 :(得分:3)

1)你真的不能确保执行总是在同一时间,但至少你可以通过使用this answer中描述的“锁定”策略来避免性能下降。

基本上你可以测试锁文件是否存在,如果存在,让你的程序睡一段时间,然后再试一次。

如果程序没有找到锁文件,它会创建它,并在执行结束时删除锁文件。

请注意:在下面的代码中,当脚本无法锁定特定数量的retries时,它将退出(但这个选择真的取决于您)。

以下代码举例说明了如何使用文件作为同一脚本的并行执行的“锁定”。

import time
import os
import sys

lockfilename = '.lock'
retries = 10
fail = True

for i in range(retries):
    try:
        lock = open(lockfilename, 'r')
        lock.close()
        time.sleep(1)
    except Exception:
        print('Got after {} retries'.format(i))
        fail = False
        lock = open(lockfilename, 'w')
        lock.write('Locked!')
        lock.close()
        break

if fail:
    print("Cannot get the lock, exiting.")
    sys.exit(2)

# program execution...
time.sleep(5)
# end of program execution

os.remove(lockfilename)

2)这意味着不同的python实例共享相同的内存池,我认为这是不可行的。

答案 1 :(得分:2)

这是我们所拥有的:

  • EC2实例类型为m3.large框,只有 2 vCPU https://aws.amazon.com/ec2/instance-types/?nc1=h_ls

  • 我们需要运行一个占用CPU和内存的脚本,当CPU不忙时需要一秒钟才能执行

  • 您正在构建一个API,而不是处理并发请求和运行Apache的需求

  • 从截图中我可以得出结论:

    • 运行5个进程时,您的CPU 100%被利用。即使运行的进程较少,它们也很可能100%被利用。所以这就是瓶颈,毫不奇怪运行的进程越多,所需的时间就越多 - 您的CPU资源只会在并发运行的脚本之间共享。

    • 每个脚本副本都会占用大约300MB的RAM,因此您有大量的备用RAM并且它不是瓶颈。屏幕截图中的free + buffers内存量确认了这一点。

  • 缺少的部分是:

    1. 是直接发送到您的apache服务器的请求还是前面有平衡器/代理?
    2. 为什么在你的例子中需要PHP?有很多解决方案可以使用python生态系统,只有在它之前没有php包装器

您的问题的答案:

  
      
  1. 一般情况下这是不可行的
  2.   

您可以做的最多是跟踪您的CPU使用情况,并确保其空闲时间不会低于某个经验阈值 - 在这种情况下,您的脚本将在或多或少固定的时间内运行。

确保您需要限制同时处理的请求数。 但如果同时向您的API发送了100个请求,您将无法并行处理它们!只有其中一些将被并行处理,而其他人则等待轮到他们。但是你的服务器不会被击倒,试图为所有人提供服务。

  
      
  1. 是和否
  2.   

,因为当通过php包装器在每个请求上启动新脚本时,您不可能在当前架构中执行某些操作。顺便说一下,每次从头开始运行一个新脚本是一项非常昂贵的操作。

如果使用其他解决方案。以下是选项:

  • 使用支持python的 pre -forking 网络服务器,它将直接处理您的请求。您可以在python启动时节省CPU资源+您可以利用一些预加载技术在工作人员之间共享RAM,即http://docs.gunicorn.org/en/stable/settings.html#preload-app。您还需要限制要运行的并行工作人员数http://docs.gunicorn.org/en/stable/settings.html#workers以满足您的第一个要求。

  • 如果您因某种原因需要 PHP ,可以在 PHP 脚本和python worker之间设置一些中介 - 即队列式服务器。 而不是简单地运行 python 脚本的几个实例,这些脚本会等待某些请求在队列中可用。一旦它可用,它将处理它并将响应放回队列,并且php脚本会啜饮它并返回给客户端。但构建它更复杂,第一个解决方案(如果你当然可以消除你的PHP脚本)和更多组件将会涉及。

  • 拒绝同时处理此类繁重请求的想法,而是为每个请求分配唯一ID ,将请求放入队列并将此ID返回给客户马上。该请求将由脱机处理程序获取,并在完成后返回队列。客户有责任轮询您的API以准备此特定请求

  • 第一个和第二个组合 - 处理 PHP 中的请求,并请求另一个HTTP服务器(或任何其他TCP服务器)处理预加载的.py-scripts

答案 2 :(得分:2)

1)

更多服务器等于更多可用性

Hearsay告诉我,确保一致请求时间的一种有效方法是对群集使用多个请求。我听到它的想法是这样的。

请求缓慢的可能性

(免责声明我不是一位数学家或统计学家。)

如果有1%的可能性请求将花费不正确的时间来完成,那么预计一百个请求可能会很慢。如果您作为客户端/消费者向群集发出两个请求而不是一个请求,那么两个请求变慢的可能性将更像是1/10000,并且有三个1/1000000,等等。缺点是您的传入请求加倍意味着需要提供(并支付)两倍的服务器功率来满足您的请求并保持一致的时间,这个额外的成本会随着慢速请求可接受的机会而增加。

据我所知,这个概念针对一致的履行时间进行了优化。

客户

与这样的服务连接的客户端必须能够生成多个请求并优雅地处理它们,可能包括尽快关闭未实现的连接。

服务器

在支持后,应该有一个负载均衡器,可以将多个传入客户端请求关联到多个唯一的集群工作者。如果一个客户端向一个负担过重的节点发出多个请求,它就会像你在简单示例中看到的那样复合自己的请求时间。

除了让客户端机会性地关闭连接之外,最好还有一个共享作业履行状态/信息的系统,以便其他其他较慢的进程节点上的积压请求有可能中止已经完成的请求。

这是一个非常非正式的答案,我没有以这种方式优化服务应用程序的直接经验。如果有人,我鼓励并欢迎更详细的编辑和专家实施意见。

2)

缓存导入

是的,这是一件事,它太棒了!

我个人建议设置django + gunicorn + nginx。 Nginx可以缓存静态内容并保留请求积压,gunicorn提供应用程序缓存和多线程和工作人员管理(更不用说真棒管理和统计工具),django嵌入了数据库迁移,身份验证,请求路由以及关闭的最佳实践用于提供语义休息端点和文档的架式插件,各种各样的优点。

如果你真的坚持自己从头开始构建它,你应该学习uWsgi,一个可以与Wsgi implementation接口的优秀gunicorn来提供应用程序缓存。 Gunicorn也不是唯一的选择,NicholasPiël比较各种python web服务应用程序的Great write up性能。

答案 3 :(得分:1)

ec2云不保证服务器上有7.5gb的可用内存。这意味着VM性能受到严重影响,就像您看到服务器的物理自由ram低于7.5gb一样。尝试减少服务器认为的内存量。

这种并行性能非常昂贵。通常需要300mb,理想情况是长时间运行的脚本,并将内存重新用于多个请求。 Unix fork函数允许重用共享状态。 os.fork在python中提供了这个,但可能与您的库不兼容。

答案 4 :(得分:0)

可能是因为计算机的运行方式。

每个程序在计算机上获得一段时间(引用Help Your Kids With Computer Programming,例如 1/1000 一秒

回答1 :尝试使用多个 threads 而不是并行进程< / strong>即可。

它不那么<强>耗时,但程序的执行时间仍然不会完全不变

注意: 每个程序都有自己的内存插槽,这就是为什么内存消耗正在拍摄。