标准输出附加到文件大小限制

标准输出附加到文件大小限制

我正在从国家公路交通安全管理局 API 中提取大约 25,000,000 个 VIN 号码的 VIN 规范。这是大量数据,并且由于我没有以任何方式转换数据,因此curl似乎是比 Python 更高效、更轻量级的完成任务的方法(因为 Python 的 GIL 使并行处理变得有点痛苦)。

在下面的代码中,vins.csv是一个包含 25M VIN 的大样本的文件,被分成 100 个 VIN 的块。这些将被传递给使用 4 个内核的 GNU Parallel。一切都nhtsa_vin_data.csv在最后倾倒。

$ cat vins.csv | parallel -j10% curl -s --data "format=csv" \
   --data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ \
      >> /nas/BIGDATA/kemri/nhtsa_vin_data.csv

这个过程一开始大约每分钟写入 3,000 个 VIN,并且随着时间的推移逐渐变慢(目前约为 1,200 个/分钟)。

我的问题

  • 我的命令中是否有任何东西会随着nhtsa_vin_data.csv规模的增长而增加开销?
  • 这与Linux处理>>操作的方式有关吗?

更新 #1 - 解决方案

每个@slm的第一个解决方案 - 使用并行的tmp文件选项将每个curl输出写入其自己的.par文件,最后合并:

$ cat vins.csv | parallel \
--tmpdir /home/kemri/vin_scraper/temp_files \
--files \
-j10% curl -s \
--data "format=csv" \
--data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ > /dev/null

cat <(head -1 $(ls *.par|head -1)) <(tail -q -n +2 *.par) > all_data.csv

@oletange 的第二个解决方案 - 使用 --line-buffer 将输出缓冲到内存而不是磁盘:

$ cat test_new_mthd_vins.csv | parallel \
    --line-buffer \
    -j10% curl -s \
    --data "format=csv" \
    --data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ \
    >> /home/kemri/vin_scraper/temp_files/nhtsa_vin_data.csv

性能考虑

我发现这里建议的两个解决方案都非常有用和有趣,并且将来肯定会更多地使用这两个版本(用于比较性能和额外的 API 工作)。希望我能够运行一些测试,看看哪一个对于我的用例表现更好。

此外,运行某种吞吐量测试(如 @oletange 和 @slm 建议)是明智的,因为 NHTSA 成为此处瓶颈的可能性是不可忽视的。

答案1

我怀疑这会导致您在分叉收集 API 数据的命令之间>>争用文件。nhtsa_vin_data.csvcurlparallel

我会这样调整你的应用程序:

$ cat p.bash
#!/bin/bash

cat vins.csv | parallel --will-cite -j10% --progress --tmpdir . --files \
   curl -s --data "format=csv" \
     --data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/

这将为您的curl命令提供自己的独立文件来写入数据。

例子

我获取了您提供给我的这 3 个 VIN 1HGCR3F95FA017875;1HGCR3F83HA034135;3FA6P0T93GR335818;,并将它们放入名为 的文件中vins.csv。然后我将它们复制了很多次,以便该文件最终具有以下特征:

每行 VIN
$ tail -1 vins.csv | grep -o ';' | wc -l
26
行数
$ wc -l vins.csv
15 vins.csv

然后我使用这些数据运行我的脚本:

$ ./p.bash

Computers / CPU cores / Max jobs to run
1:local / 1 / 1

Computer:jobs running/jobs completed/%of started jobs/Average seconds to complete
local:1/0/100%/0.0s ./pard9QD3.par
local:1/1/100%/10.0s ./paruwK9L.par
local:1/2/100%/8.5s ./parT6rCS.par
local:1/3/100%/7.3s ./pardzT2g.par
local:1/4/100%/6.8s ./parDAsaO.par
local:1/5/100%/6.8s ./par9X2Na.par
local:1/6/100%/6.7s ./par6aRla.par
local:1/7/100%/6.7s ./parNR_r4.par
local:1/8/100%/6.4s ./parVoa9k.par
local:1/9/100%/6.1s ./parXJQTc.par
local:1/10/100%/6.0s ./parDZZrp.par
local:1/11/100%/6.0s ./part0tlA.par
local:1/12/100%/5.9s ./parydQlI.par
local:1/13/100%/5.8s ./par4hkSL.par
local:1/14/100%/5.8s ./parbGwA2.par
local:0/15/100%/5.4s

把事情放在一起

当上述运行完成后,您可以将cat所有文件放在一起以获得单个.csv文件ala:

$ cat *.par > all_data.csv

执行此操作时请务必小心,因为每个文件对于其中包含的 CSV 数据都有自己的标题行。要处理从结果文件中取出标头:

$ cat <(head -1 $(ls *.par|head -1)) <(tail -q -n +2 *.par) > all_data.csv

你的表现变慢

在我的测试中,DOT 网站确实在查询继续访问其 API 时对其进行了限制。我在实验中看到的上述时间虽然很小,但随着每个查询发送到 API 网站而减少。

我在笔记本电脑上的表现如下:

$ seq 5 | parallel --will-cite --line-buffer 'yes {} | head -c 1G' | pv >> /dev/null
   5GiB 0:00:51 [99.4MiB/s] [                                                                                                                                                                  <=>       ]

笔记:以上是借用Ole Tange的回答并修改的。它通过管道写入 5GB 数据parallel并将其传输到pv >> /dev/null.pv使用它,我们可以监控通过管道的吞吐量并获得 MB/s 类型的测量结果。

我的笔记本电脑能够达到约 100MB/s 的吞吐量。

NHTSA API 常见问题解答

应用程序编程接口

对于“批量解码 VIN(平面格式)”,是否有一个通过 URL 进行此查询的示例,类似于其他操作?

对于这个特定的 API,您只需将一组 VIN 放入框中,并用“;”分隔。您还可以在“;”之前注明型号年份用“,”分隔。您可以通过此服务输入的 VIN 数量有上限。

盒内示例为样本:5UXWX7C5*BA,2011; 5YJSA3DS*EF

来源: https://vpic.nhtsa.dot.gov/MfrPortal/home/faq搜索“费率”

上面提到使用API​​有一个上限:

您可以通过此服务输入的 VIN 数量有上限。

参考

答案2

性能通常受到以下之一的限制:

  1. 网络带宽。您可以使用它sudo iftop来查看您的网络连接是否已 100% 使用。
  2. 网络延迟。如果另一端的服务器需要很长时间才能回复,那么您将不会看到 100% 的带宽利用率。
  3. 磁盘 I/O。您可以使用iostat -dkx 1它来查看任何磁盘的 I/O 是否已 100% 使用。
  4. 中央处理器。top如果您的 CPU 利用率为 100%,则可以使用。按1可查看各个 CPU 线程。如果其中之一为 100%,那么您就有一个单线程程序,受此限制。

GNU Parallel 擅长并行运行作业以利用更多带宽、磁盘 I/O 和 CPU。

但它也有其局限性。

GNU Parallel 通常将输出缓存在/tmp.这意味着您的磁盘 I/O/tmp可能是瓶颈。

幸运的是,在处理 CSV 时,您很少关心行的顺序:如果行混合也没关系,只要它是完整的行即可。

如果您使用--line-buffer版本 >20170822 则 GNU Parallel 会不是磁盘上的缓冲区输出 - 它仅在内存中缓冲一整行。这需要更多的 CPU 能力才能完成,因此请检查是否parallel使用 100% CPU。如果它使用较少,那么您还没有达到该瓶颈。

$ cat vins.csv | parallel --line-buffer curl -s --data "format=csv" \
 --data "data={1}" https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/ \
  >> /nas/BIGDATA/kemri/nhtsa_vin_data.csv

您可以通过以下方式查看是否存在本地瓶颈:

$ seq 1000 | parallel --line-buffer 'yes {} | head -c 1G' | pv >> /nas/BIGDATA/test

在我那台糟糕的笔记本电脑上,我的速度约为 100 MB/s。所以我那台糟糕的笔记本电脑将能够处理来自 dot.gov 的 1 Gbit/s。

相关内容