如何从列表中多线阅读字典并进入数据库

时间:2015-01-08 19:06:30

标签: python multithreading

我正在尝试多线程以下代码,我似乎无法让它工作。

以下代码(我为了说明目的删除了大部分代码)目前工作顺利,但速度很慢(3600条推文列表大约需要5分钟)。

import dataset
import datetime
import json

with open("postgresConnecString.txt", 'r') as f:
    DB_CONNECTIONSTRING = f.readline()
DB = dataset.connect(DB_CONNECTIONSTRING)

def load_tweet(tweet, tweets_saved):
    """Takes a tweet (dictionary) and upserts its contents to a PostgreSQL database"""
    try:
        data = {'tweet_id': tweet['tweet_id',
                'tweet_json': json.dumps(tweet)} # Dictionary that contains the data I need from the tweet
        DB['tweets'].upsert(data, ['tweet_id'])
        tweets_saved += 1
        if tweets_saved % 100 == 0:
            print('Saved ' + str(tweets_saved) + ' tweets')
        return tweets_saved
    except KeyError:
        return tweets_saved

if __name__ == "__main__":
    tweets['tweet1', 'tweet2']
    for tweet in tweets:
        tweets_saved = load_tweet(tweet, tweets_saved)

因此,我正在寻找一个选项来做这个多线程。但是,我还没有找到一种方法:

  • 多线程提取过程;
  • 每100,500或1000条推文打印一个计数器;

通过this tutorial还没有让我理解这样做:每个线程的类的概念,我需要在类中自定义并在此刻实现一个Queue是很多我此刻掌握;我只是半开始。

  • 有人可以提供关于如何使用多个线程合并上述脚本的提示吗?
  • 我应该使用多少个线程? Python目前在运行脚本时占用了大约1%的CPU,大约占RAM的10%(我的system specs
  • 如何处理递增计数器(使用Lock()?),并在点击计数器%100时打印?

编辑:根据要求:以下是分析器结果的大镜头(使用dataset.upsert):

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    5898  245.133    0.042  245.133    0.042 :0(_connect)
    5898   12.137    0.002   12.206    0.002 :0(execute)

以下是'dataset.insert'而非'dataset.upsert'的第二次尝试:

1386332 function calls (1382960 primitive calls) in 137.255 seconds

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  2955  122.646    0.042  122.646    0.042 :0             (_connect)

最后(并且绝对不是最不重要),这是运行原始psycopg2代码的时间。

63694 function calls (63680 primitive calls) in 2.203 seconds

总结一下,不要使用数据集来提高性能(尽管编写psycopg2代码花了我10分钟,这是>> datat.upsert的10秒)

  • 现在,原来的问题。通过多线程,我能够将每个文件减少~2秒吗?怎么样?

可以找到完整的代码here

2 个答案:

答案 0 :(得分:3)

可以改进的几件事情:

在单个事务上运行整个批处理。使用事务意味着数据库不需要在每次写入时实际提交(将数据写入磁盘),而是可以在内存上缓冲未提交的数据。这通常会导致更有效的资源使用。

在tweet_id上添加唯一索引。如果没有唯一索引,您可能会强制数据库对每个upsert执行顺序扫描,这会导致批量upsert按比例缩放O(n ** 2)。

拆分插入和更新,只要你可以使用.insert_many()而不是.upsert()。在执行批量upsert之前,您需要执行预检查询以查找数据库和推文列表中存在的tweet_ids列表。使用.insert_many()插入数据库中不存在的项目,并插入已存在的项目的.update()。

答案 1 :(得分:0)

我不知道你是否能够提高表现。但至于我认为你将如何想要concurrent.futures.Executor.map。 ProcessPoolExecutor而不是ThreadPoolExecutor应该是你想要的,虽然我不是专家。

https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.map

如果您想显示进度,请查看同一模块中的concurrent.futures.as_completed。