我正在使用 postgreSQL 进行科学应用(无监督聚类)。python 程序是多线程的,因此每个线程管理自己的 postmaster 进程(每个核心一个)。因此,它们具有很大的并发性。
每个线程进程无限循环执行两个 SQL 查询。第一个用于读取,第二个用于写入。读取操作考虑的行数是写入操作考虑的行数的 500 倍。
以下是 dstat 的输出:
----total-cpu-usage---- ------memory-usage----- -dsk/total- --paging-- --io/total-
usr sys idl wai hiq siq| used buff cach free| read writ| in out | read writ
4 0 32 64 0 0|3599M 63M 57G 1893M|1524k 16M| 0 0 | 98 2046
1 0 35 64 0 0|3599M 63M 57G 1892M|1204k 17M| 0 0 | 68 2062
2 0 32 66 0 0|3599M 63M 57G 1890M|1132k 17M| 0 0 | 62 2033
2 1 32 65 0 0|3599M 63M 57G 1904M|1236k 18M| 0 0 | 80 1994
2 0 31 67 0 0|3599M 63M 57G 1903M|1312k 16M| 0 0 | 70 1900
2 0 37 60 0 0|3599M 63M 57G 1899M|1116k 15M| 0 0 | 71 1594
2 1 37 60 0 0|3599M 63M 57G 1898M| 448k 17M| 0 0 | 39 2001
2 0 25 72 0 0|3599M 63M 57G 1896M|1192k 17M| 0 0 | 78 1946
1 0 40 58 0 0|3599M 63M 57G 1895M| 432k 15M| 0 0 | 38 1937
我确信我可以更频繁地写入,因为我看到它在 dstat 上写入高达 110-140M。我该如何优化这个过程?
答案1
我是 dstat 的作者,也是一名系统工程师。我注意到平均 iowait 时间为 60%。根据你的输出,我认为你的磁盘非常繁忙。你可以尝试最近 dstat 版本中的新 --disk-util 插件选项。
这将显示磁盘的利用率,我预计您使用的磁盘的利用率接近 100%。因此,考虑到您的特定 I/O 模式,您的磁盘足以处理读取或写入请求。
为什么低于基准数字?因为通常当您对磁盘吞吐量进行基准测试时,您会以对您的磁盘/缓存最佳的某种模式对磁盘施加压力(例如,使用单个线程对大块大小进行线性读取或写入),而在当前工作负载中,特定模式可能不太理想(使用多个线程以小块或不同块大小进行随机读取或写入,请求资源)。
这种模式差异会对吞吐量产生巨大影响。在实际工作负载中获得更好的吞吐量意味着您必须使用更接近实际工作负载的工作负载进行基准测试,以了解在这些条件下可以实现的最大值。或者您可以通过更改设计(例如,将应用程序中的块大小与文件系统/磁盘子系统对齐)或改进缓存和/或预读来影响实际工作负载。
如果不分析你的工作量,就没有简单的方法可以解决这个问题。
答案2
我认为这很大程度上取决于程序的代码,它可能正在等待工作线程重新同步后再开始下一个操作。
读取操作是否涉及正在写入的相同数据,如果是,则如果您停止等待其他线程赶上,则可能会出现并发/竞争条件。
最好将其移至堆栈溢出。
答案3
实际上,这很可能是 Python 代码层面的问题。Python 使用全局解释器锁来处理线程,您可能会遇到锁问题。StackOverflow 上有一篇关于吉尔和多核系统。
我会考虑使用每个邮政局长一个进程和一个“主主”来管理这些进程(如果需要),或者可能使用 Twisted 来绕过 GIL。