提高Python脚本的速度:多线程还是多实例?

提高Python脚本的速度:多线程还是多实例?,python,multithreading,performance,python-requests,Python,Multithreading,Performance,Python Requests,我有一个Python脚本,我想每天运行,我更希望它只需要1-2个小时就可以运行。目前的设置是针对给定的URL点击4个不同的API,捕获结果,然后将数据保存到PostgreSQL数据库中。问题是我有超过160000个URL需要浏览,而脚本最终需要花费很长时间——我运行了一些初步测试,以当前格式浏览每个URL需要超过36个小时。因此,我的问题归结为:我应该优化脚本以同时运行多个线程吗?或者我应该扩大使用的服务器数量吗?显然,第二种方法的成本更高,因此我更喜欢在同一个实例上运行多个线程 我正在使用我创

我有一个Python脚本,我想每天运行,我更希望它只需要1-2个小时就可以运行。目前的设置是针对给定的URL点击4个不同的API,捕获结果,然后将数据保存到PostgreSQL数据库中。问题是我有超过160000个URL需要浏览,而脚本最终需要花费很长时间——我运行了一些初步测试,以当前格式浏览每个URL需要超过36个小时。因此,我的问题归结为:我应该优化脚本以同时运行多个线程吗?或者我应该扩大使用的服务器数量吗?显然,第二种方法的成本更高,因此我更喜欢在同一个实例上运行多个线程

我正在使用我创建的库(),它提供了命中不同API端点并解析结果的方法。下面是我如何配置脚本的:

import psycopg2
from socialanalytics import pinterest
from socialanalytics import facebook
from socialanalytics import twitter
from socialanalytics import google_plus
from time import strftime, sleep

conn = psycopg2.connect("dbname='***' user='***' host='***' password='***'")
cur = conn.cursor()

# Select all URLs
cur.execute("SELECT * FROM urls;")
urls = cur.fetchall()

for url in urls:

    # Pinterest
    try:
        p = pinterest.getPins(url[2])
    except:
        p = { 'pin_count': 0 }
    # Facebook
    try:
        f = facebook.getObject(url[2])
    except:
        f = { 'comment_count': 0, 'like_count': 0, 'share_count': 0 }
    # Twitter
    try:
        t = twitter.getShares(url[2])
    except:
        t = { 'share_count': 0 }
    # Google
    try:
        g = google_plus.getPlusOnes(url[2])
    except:
        g = { 'plus_count': 0 }

    # Save results
    try:
        now = strftime("%Y-%m-%d %H:%M:%S")
        cur.execute("INSERT INTO social_stats (fetched_at, pinterest_pins, facebook_likes, facebook_shares, facebook_comments, twitter_shares, google_plus_ones) VALUES(%s, %s, %s, %s, %s, %s, %s, %s);", (now, p['pin_count'], f['like_count'], f['share_count'], f['comment_count'], t['share_count'], g['plus_count']))
        conn.commit()
    except:
        conn.rollback()
您可以看到,对API的每个调用都使用了,这是一个同步的阻塞事件。经过一些初步研究,我发现,这是一个API的顶部。Twisted的异步、非阻塞特性似乎是改进我的方法的一个很好的候选者,但我从未使用过它,而且我不确定它到底能(以及是否)帮助我实现我的目标


非常感谢您的指导

首先,您应该测量脚本在每个步骤上花费的时间。也许你会发现一些有趣的事情:)

其次,您可以将URL拆分为块:

chunk\u size=len(url)/cpu\u core\u count;//不要忘记除法的剩余部分

在这些步骤之后,您可以使用它并行处理每个块。下面是一个例子:

import multiprocessing as mp

p = mp.Pool(5)

# first solution
for urls_chunk in urls: # urls = [(url1...url6),(url7...url12)...]
    res = p.map(get_social_stat, urls_chunk)
    for record in res:
        save_to_db(record)

# or, simple
res = p.map(get_social_stat, urls)

for record in res:
   save_to_db(record)

还有,我可以帮你。因为它可以优化处理同步阻塞请求序列所花费的时间。

各种url请求是否需要共享内存空间?如果不是,一个简单的解决方案就是使用多处理。有关一些快速代码,请参阅:不,它们不需要共享内存空间。我能想到的缩短所需时间的唯一方法是运行10个进程,每个进程处理自己的URL。然而,我不确定如何做到这一点。我采用这种方法的方向正确吗?对不起,我刚收到这个。看起来一切都解决了:)我让多处理工作正常了,但现在我对Facebook的API请求数量受到了限制:(你能创建多个凭据集吗?我现在只有一个CPU(在最小的DigitalOcean droplet上运行),但是,我可以增加这是必需的。我不能在我当前的VPS上运行10个或更多进程吗?如果不能,我想我不能缩短我需要的时间——目前需要36个小时,我想把它缩短到1-4个小时。我已经将
for
循环的逻辑提取到它们自己的函数中,但我仍然不知道re如何设置多处理部分。你能看一下吗?当然,你可以生成10个进程。但最好是通过性能测试找到最佳数量。尝试使用不同数量的进程解析100个URL。尝试以70-80%的百分比加载你的cpu。我使用了上面的代码,发现10个进程只使我的cpu使用率提高到35%左右。然而,经过几次测试,我发现我达到了Facebook API的极限。我现在得到了
(#4)应用程序请求限制已达到。
。感谢您的帮助!我实际上注意到上面的代码有问题。如果我从100个url开始,我在
res
列表中只得到50个项目。您知道为什么会发生这种情况吗?下面是代码,以及它产生的输出:看起来只有
url\u块的后半部分
are进入
res
列表。知道为什么上半部分没有被包括在内吗?