
为什么要用h5
------------

比如需要将一个词典保存到磁盘，词典很小直接pickle.dumps就行，读取也直接pickle.loads, 但是当词典很大，比如一亿的时候，这时候可能需要做一些操作


* 将词典分割，分次很多份分别存储
* 使用h5

第一种方法存起来没什么问题，但是随机读取会很慢，比如一批random的key，key可能分散在所有的分片中，因此需要将所有的词典load到内存一遍，耗费大量时间。
这应该是一个经典的数据库的问题，但是有时候又不想用很重的数据库，可选项就剩下


#. 使用轻量级的数据库，例如sqlite3、leveldb等
#. 使用h5

前者不在我们今天的讨论范围，这里主要是讲一下h5的一些性能实测，和一些高效使用的方法。

读写测试
--------

关于groups
^^^^^^^^^^

一般来讲的话先建groups，再建dataset，理论上groups越多，读写效率越高。
在MacBook Pro 16-inch, 2019上的测试数据如下:

.. list-table::
   :header-rows: 1

   * - Item
     - groups=1
     - groups=10
     - groups=100
     - groups=1000
   * - 10w数据内存峰值(M)
     - 96.3
     - 92.9
     - 97.4
     - 101
   * - 10w数据插入时间
     - 19.06
     - 19.08
     - 19.31
     - 21.51
   * - 10w数据读取1w条
     - 2.46
     - 2.59
     - 2.65
     - 2.58
   * - 100w数据插入时间
     - 188.34
     - 190.99
     - 190.16
     - 199.78
   * - 100w数据读取1w条
     - 4.35
     - 5.82
     - 4.14
     - 4.28
   * - 1000w数据插入时间
     - ~
     - ~
     - ~
     - 约1小时
   * - 1000w数据读取1w条
     - ~
     - ~
     - ~
     - 9.92


前面10w和100w试验的时候，差距很小，甚至groups=1反而更快。但是当数据量提升到1000w的时候，差距变得很明显, group=1的情况无法完成, groups=100和1000至少相差一倍时间。

结论就是在数据量极大的情况下，必须用多个ngroups。

多进程/线程同时读
^^^^^^^^^^^^^^^^^

注意直接多进程，会有一些问题；需要这样，加入swmr（single write multiple read）

.. code-block:: python

   h5py.File('./data_1000.h5', 'r', swmr=True)

下面是一个300w的数据库，单/多进程测试结果：

.. list-table::
   :header-rows: 1

   * - 
     - n_process = 1
     - n_process = 2
     - n_process = 10
     - n_process = 100
   * - 0.1w条query
     - 0.66
     - 0.27
     - 0.13
     - 0.28
   * - 1w条query
     - 8.8
     - 4.3
     - 1.1
     - 1.3
   * - 10w条query
     - 67.9
     - 34.4
     - 7.9
     - 8.21


可以看出来，多进程读效果提升非常明显，但是肯定也不是越多越好，带来很多额外开销。

关于blocks大小
^^^^^^^^^^^^^^

测试方法，30w次读写速度，测试单次插入数据量的大小对最终结果的影响

.. list-table::
   :header-rows: 1

   * - 单次插入数据量
     - 0.1k
     - 1k
     - 10k
     - 100k
   * - 写入时间(秒)
     - 60.25
     - 62.25
     - 66.96
     - 195.95
   * - 1w次读取时间(秒)
     - 2.52
     - 2.6
     - 5.88
     - 7.91


可以看出来，读取速度对blocks大小敏感度没有那么大，数据量增大1000倍，读取时间增长到3倍，写入速度也是三倍，但是并非线性。
