繁体   English   中英

使用Postgresql的Python多线程

[英]Python multi-threading with Postgresql

我有一个非常基本的应用程序,该应用程序通过套接字连接从服务器下载数据,一次只记录一个记录,并将每个记录写到postgresql数据库中。 这仅由我使用。

downloader = DataDownloader.Downloader()
con = psycopg2.connect(datebase='db', user='username', password='pswrd')

downloader.get_data(con)
con.close()

在上面的代码中,我将psycopg2连接传递给一个类的实例,该类随后执行所有下载和数据库更新。

问题在于,此过程极其缓慢,因为在get_data() ,该类一次仅下载一个记录。 我已经开始更改它以合并线程:

downloader = DataDownloader.Downloader()

records_to_download = 'abc'
thread1 = threading.Thread(target=downloader.get_data, args=(records_to_download))
thread1.start()

records_to_download = 'xyz'
thread2 = threading.Thread(target=downloader.get_data, args=(records_to_download))
thread2.start()

records_to_download = 'ghj'
thread3 = threading.Thread(target=downloader.get_data, args=(records_to_download))
thread3.start()

我所做的只是再次创建一个downloader实例。 然后创建3个线程,每个线程通过向其传递一个参数指定要下载的记录来运行get_data

我没有创建psycopg2连接并将其传递给get_data而是在get_data创建了连接,以便每个线程都有自己的连接。

我的问题是,是否足够且正确,以确保所有线程将同时与数据库“良好配合”? 每个线程仍在使用相同的用户名/密码来访问数据库。 我已经通过向每个线程传递records_to_download参数来确保每个线程将更新不同的记录。

我听说过连接池,但是对于一个用户来说,这样的多线程设置是否太过苛刻? (我从未使用过连接池,并且我的数据库知识非常基础,因此,如果没有必要,我会避免使用它)。

最后,在被迫使用更强大的方法(例如连接池)之前,我可以用于这种设置的线程数有限制吗? 还是一开始就需要连接池?

是否足够并正确,以确保所有线程将同时与数据库“良好配合”?

确实,这是实现并行性的最直接方法。

(请注意,事实上PostgreSQL通过单个连接支持并行性,但据我所知,它仅可在C驱动程序中使用 。还有executemany和使用单个INSERT语句插入多行的技巧(参见此问题 )) 。

现在您已经通过多个连接实现了高效的并行性,现在应该检查服务器端瓶颈。 特别是,以ACID要求的超耐用方式将事务提交到磁盘可能会导致更新缓慢,因为它们正在等待操作系统和存储设备报告有效负载的成功到达。

为此,您可能希望通过在用于批量更新的每个连接中将SET synchronous_commit TO off ,从而使持久性有所放松。 (参看synchronous_commit这个问题 )。

或者,您可以将更新分组到大型事务中,从而将磁盘持久性问题延迟到事务提交之前。

我听说过连接池,但是对于一个用户来说,这样的多线程设置是否太过苛刻?

连接池主要用于减轻建立和拆除连接的成本。 在某些设置中,它还可以减少数据库需要维护的连接数。

考虑以下用例:1)用户访问服务器页面; 2)服务器建立数据库连接; 3)服务器通过查询数据库检查用户是否存在; 4)服务器断开连接; 5)服务器将页面发送给用户。

在这种重复性任务中,通常使用某种类型的连接池来优化第二步和第四步。

另一个用例:1)用户访问服务器页面; 2)服务器进程建立并缓存数据库连接; 3)服务器通过查询数据库检查用户是否存在; 4)服务器将页面发送给用户。

在这里,每个服务器进程都保持自己的数据库连接,以便每次有请求时都不会建立新的数据库连接。 因此,如果您有200个PHP进程在运行,那么就有200个数据库连接。 这需要数据库服务器的RAM来维护连接。 可以改用连接池,以达到类似的性能而无需维持200个连接。

在您的方案中,我认为不需要连接池。 还拥有自己的连接,可以让你调整它们进一步与synchronous_commitwork_mem等,使用连接池时,因为留在池中微调的连接时,您可能会影响以不受控制的方式耐久性及其他泳池用户的性能是不可取。

最后,在被迫使用更强大的方法(例如连接池)之前,我可以用于这种设置的线程数有限制吗? 还是一开始就需要连接池?

多线程不是灵丹妙药。 您只需要尽可能多的线程和连接来解决由于驱动程序与数据库通信的串行性质而造成的瓶颈(实际上,如果您要使用C语言驱动程序的异步管道版本,则可能不需要在所有),并达到由数据库服务器配置和硬件强加的性能指标。 在问题上抛出过多的线程只会使系统分散,使它的运行速度甚至更慢(请参阅性能降低的原因超过“膝盖” )。

测试并测量以得出针对您的用例的最佳线程和连接数。

性能是您的极限,在该问题上投入过多线程会降低性能。

至于连接池,仅在特定的用例中才需要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM