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

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

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

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

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



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

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


| 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）
```python
h5py.File('./data_1000.h5', 'r', swmr=True)
```

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

|    | 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次读写速度，测试单次插入数据量的大小对最终结果的影响


|  单次插入数据量  | 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倍，写入速度也是三倍，但是并非线性。
