使用Django和python 2.7。我有一张包含数百万行的Excel表格。我必须操纵行数据并保存回数据库(postgresql)。我想有效地做到这一点。 以下是我想到的方法:
1。)将队列中的所有行(数据)排入队列(最好是RabbitMQ),并一次取出一堆100个条目。并将执行和 将它保存在数据库中。
2.)考虑在后台使用线程,每个线程将管理100行,并将结果保存到数据库中。我不是 确定在这种情况下将打开多少个数据库连接。
您能否建议我实现这一目标的有效方法。这将非常有帮助。
答案 0 :(得分:1)
您可以在Django请求处理程序中创建其他线程,每个线程都有自己的数据库连接。但问题就变成了,你的数据库在多个theads中的性能提升了多少?
例如,如果您的表具有唯一约束,则会降低并发写入的速度。然后你可能会发现你的真正瓶颈是磁盘带宽,并且你无法通过添加连接来扩展太多。
因此,在进行优化之前,您可能需要编写一些快速且肮脏的测试代码来尝试对相关表或数据库进行多线程并发写入。
至于如何在线程之间有效地划分数据,这取决于输入格式。
如果您正在处理Microsoft格式文件,例如.xls
,那么您将需要使用库来解析它...我已成功使用xlrd
。但这会导致您的所有电子表格数据同时存在于内存中......您无法一次读取一行。但假设您可以处理内存使用情况,它会使您的线程变得简单:一旦您将所有数据读入内存,就会启动多个编写器线程,告诉每个编写器线程负责编写的行号。然后,主请求线程可以只加入编写器线程,当它们全部完成时,它可以向用户返回响应。但是,请记住,如果您的请求耗时太长,浏览器将超时。这是一个不同的问题,为此,我建议看看我前几天写的关于如何使用StreamingHttpResponse
的另一个答案:
Right way to delay file download in Django
现在,如果您的输入格式类似于.csv
文件,您可以一次读取一条记录,处理此问题的一种可能方法是使用python {{1创建内存中队列class(https://docs.python.org/2/library/queue.html)。启动编写器线程并让它们在队列中侦听写入数据库的记录,然后让主线程一次从Queue
文件读取一条记录并将这些记录放入队列中。
这些建议都是为了在Django请求中处理您的数据。但如果您不想这样做,是的,您可以通过各种方式卸载处理。您当然可以使用.csv
,如上所述,并且有多个侦听器进程正在编写。这将有效,但我不确定它是否会达到最佳效率。您需要编写所有记录,因此将它们分解,将它们发送到另一个进程,然后将它们从那里运送到另一个进程并不一定有用......除非这些其他进程在其他计算机上运行。
如果您正在从已经写入磁盘的文件中读取数据,并且它是一种易于整除的文件格式(再次,例如CSV),那么一种简单(非常经典)的方法就是将文件大小除以您拥有的编写器线程数。告诉每个作者您希望它处理的文件的开始和结束偏移量。每个编写器(从偏移0开始的编写器除外)可以向前搜索,直到找到记录分隔符(例如rabbitmq
)。然后它开始一次读取和处理输入记录,直到它读取到等于或超过其结束偏移的位置。
如果您正在从Request中读取文件,并且想要在请求处理程序之外处理它,您可能会发现将它作为一个大文件写入磁盘更高效,然后处理它之后如上所述。
总之,尝试找到处理涉及最少读写次数的数据的方法。如果可以,就地处理数据,如果不需要,不要移动它。如果它们位于同一台机器上,则应避免写入其他进程,因为手头的进程是磁盘密集型的。如果您确实希望能够轻松扩展到更多计算机,请务必尝试\r\n
。我用它,它很好,而且很快。但它会增加开销,所以除非你从破坏事件中获得一些真正的好处,否则它可能会让你失望。它确实使进程间通信非常容易。