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