我遇到了这样的问题:我需要使用>保存一个大图。百万边缘到txt文件。每个边用一个包含3个整数的结构表示:from,to,cost。我的任务是编写一个程序,将以整个格式快速将整个图形保存到txt文件:"从成本\ n"。
我对这个方法感兴趣,怎么做。 我的想法是创建一个巨大的字符缓冲区,我将每个数字添加到缓冲区而不需要反转(首先我得到每个整数的位数,然后将每个数字添加到缓冲区,然后我添加空格/换行符号,直到添加最后一个数字为止。
然后我使用fwrite()函数将整个缓冲区保存到文件中。
尽管这种方法相对较快,但我看到程序更快。我的问题是:你知道更有效的方法来实现这个程序,以获得更快的结果吗?
该程序必须使用C语言。
columnMenuClick(args){
if(args.item.id === 'gridclearsorting'){
this.grid.clearSorting();
}
}
获取位数的函数:
typedef struct {
int edge_start;
int edge_count;
int parent;
int cost;
} node_t;
typedef struct {
graph_t *graph;
node_t *nodes;
int num_nodes;
int start_node;
} dijkstra_t;
保存功能:
int getNumberOfDigitsBig(int x) {
if (x >= 10000) {
if (x >= 10000000) {
if (x >= 100000000) {
if (x >= 1000000000)
return 9;
return 8;
}
return 7;
}
if (x >= 100000) {
if (x >= 1000000)
return 6;
return 5;
}
return 4;
}
if (x >= 100) {
if (x >= 1000)
return 3;
return 2;
}
if (x >= 10)
return 1;
return 0;
}
感谢您的关注。
答案 0 :(得分:0)
我认为你需要的是printf的优化版本,它只处理正整数。我没有对它进行基准测试,但是我会尝试做尽可能少的比较和操作,所以我以这个函数结束:
int printint(FILE *fd, int n) {
char buffer[32]; // an uint64_t uses max 20 chars in base 10
int i = sizeof(buffer);
do {
buffer[--i] = '0' + n%10; // write digits from the right of buffer
n /= 10;
} while(n > 0);
return fwrite(buffer + i, 1, sizeof(buffer) - i, fd);
}
然后我不会使用巨大的缓冲区,而只依赖于FILE *的默认缓冲
然后可以保存代码(或多或少只是从问题的示例开始):
const dijkstra_t *const dij = (dijkstra_t*)dijkstra;
if (dij) {
FILE *f = fopen(filename, "w");
if (f) {
int numberOfNodes = dij->num_nodes;
fputs("0 0 -1\n", f);
for(int i = 1; i < numberOfNodes; i++) {
const node_t *const node = &(dij->nodes[i]);
fputc(' ', f);
number = node->parent;
//printf("parent = %d\n", number);
if(number != -1) {
printint(number, f);
} else {
fwrite("-1", 1, 2, f);
}
fputc('\n', f);
}
ret = fclose(f) == 0;
free(buffer);
}
}
答案 1 :(得分:0)
使用“itoa”可以改善一点:
void gwf_i2a(char *d, int i, int l) {
char *e = d + l;
while (l > 0) {
e--;
l--;
e[0] = '0' + (i % 10);
i /= 10;
}
}
原始时间:76次点击(7.6e-05秒)。
新时间:39次点击(3.9e-05秒)。
源:
#include <ctime>
#include <iostream>
#include <random>
#include <vector>
#define ZERO '0'
void gwf_i2a(char *d, int i, int l) {
char *e = d + l;
while (l > 0) {
e--;
l--;
e[0] = '0' + (i % 10);
i /= 10;
}
}
typedef struct {
int x, y, z;
} graph_t;
typedef struct {
int edge_start;
int edge_count;
int parent;
int cost;
} node_t;
typedef struct {
graph_t *graph;
node_t *nodes;
int num_nodes;
int start_node;
} dijkstra_t;
graph_t graph = {111, 222, 3456789};
node_t nodes[] = {{1, 1, 1, 9999}, {2, 2, 2, 8999}, {2, 2, 2, 1234567890}};
dijkstra_t data[] = {&graph, (node_t *)&nodes, 4, 0};
int getNumberOfDigits(int x) {
if (x >= 100) {
if (x >= 1000) return 3;
return 2;
}
if (x >= 10) return 1;
return 0;
}
int getNumberOfDigitsBig(int x) {
if (x >= 10000) {
if (x >= 10000000) {
if (x >= 100000000) {
if (x >= 1000000000) return 9;
return 8;
}
return 7;
}
if (x >= 100000) {
if (x >= 1000000) return 6;
return 5;
}
return 4;
}
if (x >= 100) {
if (x >= 1000) return 3;
return 2;
}
if (x >= 10) return 1;
return 0;
}
void save(const char *filename, const dijkstra_t *dijkstra) {
int ret;
const dijkstra_t *const dij = (dijkstra_t *)dijkstra;
char *buffer;
if (dij) {
FILE *f = fopen(filename, "w");
if (f) {
int numberOfNodes = dij->num_nodes;
long bufferLength = numberOfNodes * (9 * 3 + 3);
buffer = (char *)malloc(bufferLength + 1);
long bufferCounter = 0;
int number;
// printf("i = %d\n", number);
int counter;
int digits;
buffer[bufferCounter++] = '0';
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = '0';
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
buffer[bufferCounter++] = '\n';
for (int i = 1; i < numberOfNodes; i++) {
const node_t *const node = &(dij->nodes[i]);
number = i;
digits = getNumberOfDigits(number);
counter = bufferCounter;
do {
buffer[counter + digits] = ZERO + number % 10;
--digits;
++bufferCounter;
} while (number /= 10);
buffer[bufferCounter++] = ' ';
number = node->cost;
if (number != -1) {
digits = getNumberOfDigitsBig(number);
counter = bufferCounter;
do {
buffer[counter + digits] = ZERO + number % 10;
digits = digits - 1;
bufferCounter = bufferCounter + 1;
} while (number /= 10);
} else {
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
}
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = ' ';
number = node->parent;
if (number != -1) {
digits = getNumberOfDigitsBig(number);
counter = bufferCounter;
do {
buffer[counter + digits] = ZERO + number % 10;
--digits;
++bufferCounter;
} while (number /= 10);
} else {
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
}
buffer[bufferCounter++] = '\n';
}
fwrite(buffer, 1, bufferCounter, f);
ret = fclose(f) == 0;
free(buffer);
}
}
}
void new_save(const char *filename, const dijkstra_t *dijkstra) {
int ret;
const dijkstra_t *const dij = (dijkstra_t *)dijkstra;
char *buffer;
if (dij) {
FILE *f = fopen(filename, "w");
if (f) {
int numberOfNodes = dij->num_nodes;
long bufferLength = numberOfNodes * (9 * 3 + 3);
buffer = (char *)malloc(bufferLength + 1);
long bufferCounter = 0;
int number;
int counter;
int digits;
buffer[bufferCounter++] = '0';
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = '0';
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
buffer[bufferCounter++] = '\n';
for (int i = 1; i < numberOfNodes; i++) {
const node_t *const node = &(dij->nodes[i]);
int len = getNumberOfDigits(i) + 1;
gwf_i2a((char *)&buffer[bufferCounter], i, len);
bufferCounter += len;
buffer[bufferCounter++] = ' ';
number = node->cost;
if (number != -1) {
len = getNumberOfDigitsBig(number) + 1;
gwf_i2a((char *)&buffer[bufferCounter], number, len);
bufferCounter += len;
} else {
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
}
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = ' ';
number = node->parent;
if (number != -1) {
digits = getNumberOfDigitsBig(number);
counter = bufferCounter;
do {
buffer[counter + digits] = ZERO + number % 10;
--digits;
++bufferCounter;
} while (number /= 10);
} else {
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
}
buffer[bufferCounter++] = '\n';
}
fwrite(buffer, 1, bufferCounter, f);
ret = fclose(f) == 0;
free(buffer);
}
}
}
void original() {
clock_t t;
t = clock();
save("bogus.txt", data);
t = clock() - t;
std::cout << "original: " << t << " clicks (" << ((float)t) / CLOCKS_PER_SEC
<< " seconds)." << std::endl;
}
void new_test() {
clock_t t;
t = clock();
new_save("new_bogus.txt", data);
t = clock() - t;
std::cout << "NEW: " << t << " clicks (" << ((float)t) / CLOCKS_PER_SEC
<< " seconds)." << std::endl;
}
int main(int argc, char **argv) {
original();
new_test();
return 0;
}
答案 2 :(得分:0)
[改写于2018-01-13。]
标准I / O(printf()
等)在将数字数据转换为文本形式方面确实相对较慢。这里的问题是输出表格行
&lt; node&gt; &lt; cost&gt; &lt; parent&gt;
其中所有三个都是十进制表示法的无符号(32位)整数,或-1。为简单起见,我们为UINT32_MAX
保留值-1
(4294967295)。
我建议采用双重方法:
从右到左构造每条记录。这样就无需检查数字中有多少位数。
一次缓冲多个记录。这减少了fwrite()
次调用的次数,代价是适度的动态分配缓冲区。
请注意,这意味着每个块中的记录必须从头到尾处理,以保持正确的顺序。
请考虑以下代码。请注意,我已将node_t
和dijkstra_t
的定义缩减为实际使用区域的字段,以便可以按原样编译以下示例。另请注意,-1
或parent
代替cost
,必须使用UINT32_MAX
,因为其类型现为uint32_t
。
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <stdio.h>
typedef struct {
uint32_t parent; /* Use UINT32_MAX for -1 */
uint32_t cost; /* Use UINT32_MAX for -1 */
} node_t;
typedef struct {
node_t *nodes;
uint32_t num_nodes;
} dijkstra_t;
/* This function will store an unsigned 32-bit value
in decimal form, ending at 'end'.
UINT32_MAX will be written as "-1", however.
Returns a pointer to the start of the value.
*/
static inline char *prepend_value(char *end, uint32_t value)
{
if (value == UINT32_MAX) {
*(--end) = '1';
*(--end) = '-';
} else {
do {
*(--end) = '0' + (value % 10u);
value /= 10u;
} while (value);
}
return end;
}
/* Each record consists of three unsigned 32-bit integers,
each at most 10 characters, with spaces in between
and a newline at end. Thus, at most 33 characters. */
#define RECORD_MAXLEN 33
/* We process records in chunks of 16384.
Maximum number of records (nodes) is 2**32 - 2 - RECORD_CHUNK,
or 4,294,950,910 in this case. */
#define RECORD_CHUNK 16384
/* Each chunk of record is up to CHUNK_CHARS long.
(Roughly half a megabyte in this case.) */
#define CHUNK_CHARS (RECORD_MAXLEN * RECORD_CHUNK)
/* Save the edges in a graph to a stream.
Returns 0 if success, -1 if an error occurs.
*/
int save_edges(dijkstra_t *dij, FILE *out)
{
if (dij && out && !ferror(out)) {
const int nodes = dij->num_nodes;
const node_t *node = dij->nodes;
const uint32_t root_parent = dij->nodes->parent;
const uint32_t root_cost = dij->nodes->cost;
char *buf, *end, *ptr;
uint32_t o;
/* Allocate memory for the chunk buffer. */
buf = malloc(CHUNK_CHARS);
if (!buf)
return -1;
end = buf + CHUNK_CHARS;
/* Temporarily, we reset the root node parent
to UINT32_MAX and cost to 0, so that the
very first record in the output is "0 0 -1". */
dij->nodes->cost = 0;
dij->nodes->parent = UINT32_MAX;
for (o = 0; o < nodes; o += RECORD_CHUNK) {
uint32_t i = (o + RECORD_CHUNK < nodes) ? o + RECORD_CHUNK : nodes;
/* Fill buffer back-to-front. */
ptr = end;
while (i-->o) {
const node_t *curr = node + i;
/* Format: <i> ' ' <cost> ' ' <parent> '\n' */
/* We construct the record from right to left. */
*(--ptr) = '\n';
ptr = prepend_value(ptr, curr->parent);
*(--ptr) = ' ';
ptr = prepend_value(ptr, curr->cost);
*(--ptr) = ' ';
ptr = prepend_value(ptr, i);
}
/* Write the chunk buffer out. */
if (fwrite(ptr, 1, (size_t)(end - ptr), out) != (size_t)(end - ptr)) {
dij->nodes->cost = root_cost;
dij->nodes->parent = root_parent;
free(buf);
return -1;
}
}
/* Reset root node, and free the buffer. */
dij->nodes->cost = root_cost;
dij->nodes->parent = root_parent;
free(buf);
/* Check for write errors. */
if (fflush(out))
return -1;
if (ferror(out))
return -1;
/* Success. */
return 0;
}
return -1;
}
如果我们可以使用来自<unistd.h>
的POSIX低级I / O(open()
,close()
,write()
和fstat()
,则可以实现额外的加速)。当目的地是管道或设备时,我们可以直接写入数据;当目标是文件时,我们应该写入st_blksize
的倍数的块,以避免读 - 修改 - 写周期。与标准I / O不同,对于低级I / O,我们可以使用st_blksize
的一个“溢出”缓冲区来完成,而无需在内存中复制整个块缓冲区。但是,由于问题没有标记为posix,我将不再进行进一步的讨论。
fwrite()
调用中写入,因为它只进行部分写入;实际编写整个数据集需要一个循环。因此,在我看来,基准OP用来比较不同版本是非常可疑的。
请考虑以下微基准测试。它生成一个单链表,并使用外部编译的save_graph()
函数将其输出(到标准输出)。实现了三个版本: null ,它根本不保存任何内容; antonkretov ,用于OP的实施(适用于此处工作);我的 nominalanimal 。
<强>生成文件强>:
CC := gcc
CFLAGS := -std=c99 -O2 -Wall
LDFLAGS :=
BINS := test-null test-antonkretov test-nominalanimal
NODES := 100000000
.PHONY: all clean run
all: clean $(BINS)
clean:
rm -f $(BINS) *.o
%.o: %.c
$(CC) $(CFLAGS) -c $^
test-null: main.o data-null.o
$(CC) $(CFLAGS) $^ -o $@
test-antonkretov: main.o data-antonkretov.o
$(CC) $(CFLAGS) $^ -o $@
test-nominalanimal: main.o data-nominalanimal.o
$(CC) $(CFLAGS) $^ -o $@
run: $(BINS)
@echo "Testing $(NODES) nodes."
@./test-null $(NODES) > /dev/null
@echo "Overhead (nothing saved):"
@bash -c 'time ./test-null $(NODES) > /dev/null'
@echo ""
@echo "Anton Kretov:"
@bash -c 'time ./test-antonkretov $(NODES) > /dev/null'
@echo ""
@echo "Nominal Animal:"
@bash -c 'time ./test-nominalanimal $(NODES) > /dev/null'
@echo ""
请注意,此论坛将 Tab 转换为空格,而Makefile格式要求缩进使用空格,因此如果您将上述内容复制并粘贴到文件中,则需要运行以下操作: sed -e 's|^ *|\t|' -i Makefile
来修复它。
<强> data.h 强>:
#ifndef DATA_H
#define DATA_H
#include <stdint.h>
#include <limits.h>
#include <stdio.h>
#define INVALID_COST UINT32_MAX
#define INVALID_PARENT UINT32_MAX
typedef struct {
uint32_t parent; /* Use INVALID_PARENT for -1 */
uint32_t cost; /* Use INVALID_COST for -1 */
} node_t;
typedef struct {
node_t *nodes;
uint32_t num_nodes;
} dijkstra_t;
int save_graph(dijkstra_t *, FILE *);
#endif /* DATA_H */
data-null.c ,用于衡量运行时开销:
#include "data.h"
int save_graph(dijkstra_t *dij, FILE *out)
{
/* Does not do anything */
return 0;
}
data-antonkretov.c ,OP的保存程序版本,用于比较:
#include <stdlib.h>
#include "data.h"
int getNumberOfDigits(uint32_t x)
{
if (x >= 10000) {
if (x >= 10000000) {
if (x >= 100000000) {
if (x >= 1000000000)
return 9;
return 8;
}
return 7;
}
if (x >= 100000) {
if (x >= 1000000)
return 6;
return 5;
}
return 4;
}
if (x >= 100) {
if (x >= 1000)
return 3;
return 2;
}
if (x >= 10)
return 1;
return 0;
}
int save_graph(dijkstra_t *dij, FILE *out)
{
uint32_t numberOfNodes = dij->num_nodes;
size_t bufferLength = numberOfNodes * (size_t)33;
size_t bufferCounter = 0, counter;
size_t bytes;
uint32_t number, digits, i;
char *buffer;
if ((size_t)(bufferLength / 33) != numberOfNodes)
return -1;
buffer = malloc(bufferLength);
if (!buffer)
return -1;
buffer[bufferCounter++] = '0';
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = '0';
buffer[bufferCounter++] = ' ';
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
buffer[bufferCounter++] = '\n';
for (i = 1; i < numberOfNodes; i++) {
const node_t *const node = dij->nodes + i;
number = i;
digits = getNumberOfDigits(number);
counter = bufferCounter;
do {
buffer[counter + digits] = '0' + (number % 10u);
--digits;
++bufferCounter;
} while (number /= 10u);
buffer[bufferCounter++] = ' ';
number = node->cost;
if (number != UINT32_MAX) {
digits = getNumberOfDigits(number);
counter = bufferCounter;
do {
buffer[counter + digits] = '0' + (number % 10u);
--digits;
++bufferCounter;
} while (number /= 10u);
} else {
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
}
buffer[bufferCounter++] = ' ';
number = node->parent;
if (number != UINT32_MAX) {
digits = getNumberOfDigits(number);
counter = bufferCounter;
do {
buffer[counter + digits] = '0' + (number % 10u);
--digits;
++bufferCounter;
} while (number /= 10u);
} else {
buffer[bufferCounter++] = '-';
buffer[bufferCounter++] = '1';
}
buffer[bufferCounter++] = '\n';
}
counter = 0;
while (counter < bufferCounter) {
bytes = fwrite(buffer + counter, 1, bufferCounter - counter, out);
if (!bytes) {
free(buffer);
return -1;
}
counter += bytes;
}
free(buffer);
return 0;
}
data-nominalanimal.c ,我的保存例程的前后版本:
#include <stdlib.h>
#include "data.h"
/* This function will store an unsigned 32-bit value
in decimal form, ending at 'end'.
UINT32_MAX will be written as "-1", however.
Returns a pointer to the start of the value.
*/
static inline char *prepend_value(char *end, uint32_t value)
{
if (value == UINT32_MAX) {
*(--end) = '1';
*(--end) = '-';
} else {
do {
*(--end) = '0' + (value % 10u);
value /= 10u;
} while (value);
}
return end;
}
/* Each record consists of three unsigned 32-bit integers,
each at most 10 characters, with spaces in between
and a newline at end. Thus, at most 33 characters. */
#define RECORD_MAXLEN 33
/* We process records in chunks of 16384.
Maximum number of records (nodes) is 2**32 - 2 - RECORD_CHUNK,
or 4,294,950,910 in this case. */
#define RECORD_CHUNK 16384
/* Each chunk of record is up to CHUNK_CHARS long.
(Roughly half a megabyte in this case.) */
#define CHUNK_CHARS (RECORD_MAXLEN * RECORD_CHUNK)
/* Save the edges in a graph to a stream.
Returns 0 if success, -1 if an error occurs.
*/
int save_graph(dijkstra_t *dij, FILE *out)
{
if (dij && out && !ferror(out)) {
const int nodes = dij->num_nodes;
const node_t *node = dij->nodes;
const uint32_t root_parent = dij->nodes->parent;
const uint32_t root_cost = dij->nodes->cost;
char *buf, *end, *ptr;
uint32_t o;
/* Allocate memory for the chunk buffer. */
buf = malloc(CHUNK_CHARS);
if (!buf)
return -1;
end = buf + CHUNK_CHARS;
/* Temporarily, we reset the root node parent
to UINT32_MAX and cost to 0, so that the
very first record in the output is "0 0 -1". */
dij->nodes->cost = 0;
dij->nodes->parent = UINT32_MAX;
for (o = 0; o < nodes; o += RECORD_CHUNK) {
uint32_t i = (o + RECORD_CHUNK < nodes) ? o + RECORD_CHUNK : nodes;
/* Fill buffer back-to-front. */
ptr = end;
while (i-->o) {
const node_t *curr = node + i;
/* Format: <i> ' ' <cost> ' ' <parent> '\n' */
/* We construct the record from right to left. */
*(--ptr) = '\n';
ptr = prepend_value(ptr, curr->parent);
*(--ptr) = ' ';
ptr = prepend_value(ptr, curr->cost);
*(--ptr) = ' ';
ptr = prepend_value(ptr, i);
}
/* Write buffer. */
if (fwrite(ptr, 1, (size_t)(end - ptr), out) != (size_t)(end - ptr)) {
dij->nodes->cost = root_cost;
dij->nodes->parent = root_parent;
free(buf);
return -1;
}
}
/* Reset root node, and free the buffer. */
dij->nodes->cost = root_cost;
dij->nodes->parent = root_parent;
free(buf);
if (fflush(out))
return -1;
if (ferror(out))
return -1;
return 0;
}
return -1;
}
最后是主程序本身 main.c ,它生成数据并调用save_graph()
函数:
#include <stdlib.h>
#include <inttypes.h>
#include <limits.h>
#include <string.h>
#include "data.h"
#define EDGES_MAX 4294901759
int main(int argc, char *argv[])
{
dijkstra_t graph;
size_t bytes;
uint32_t edges, i;
char dummy;
if (argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\nUsage: %s EDGES\n\n", argv[0]);
return EXIT_SUCCESS;
}
if (sscanf(argv[1], " %" SCNu32 " %c", &edges, &dummy) != 1 || edges < 1 || edges > EDGES_MAX) {
fprintf(stderr, "%s: Invalid number of edges.\n", argv[1]);
return EXIT_FAILURE;
}
bytes = (1 + (size_t)edges) * sizeof graph.nodes[0];
if ((size_t)(bytes / (1 + (size_t)edges)) != sizeof graph.nodes[0]) {
fprintf(stderr, "%s: Too many edges.\n", argv[1]);
return EXIT_FAILURE;
}
graph.num_nodes = edges + 1;
graph.nodes = malloc(bytes);
if (!graph.nodes) {
fprintf(stderr, "%s: Too many edges: out of memory.\n", argv[1]);
return EXIT_FAILURE;
}
/* Generate a graph; no randomness, to keep timing steady. */
graph.nodes[0].parent = INVALID_COST;
graph.nodes[0].cost = 0;
for (i = 1; i <= edges; i++) {
graph.nodes[i].parent = i - 1;
graph.nodes[i].cost = 1 + (i % 10);
}
/* Print graph. */
if (save_graph(&graph, stdout)) {
fprintf(stderr, "Write error!\n");
return EXIT_FAILURE;
}
/* Done. */
return EXIT_SUCCESS;
}
运行make clean run
(或make NODES=100000000 clean run
)重新编译基准测试,并测量其运行时间,以获得100,000,000个节点的图表。在我的机器上,输出是
Testing 100000000 nodes.
Overhead (nothing saved):
real0m0.514s
user0m0.297s
sys0m0.217s
Anton Kretov:
real0m4.059s
user0m3.379s
sys0m0.680s
Nominal Animal:
real0m3.336s
user0m3.151s
sys0m0.184s
表明我的速度明显更快。如果我们忽略了生成图表的开销,我花了大约2.8秒的实时时间将数据保存到/dev/null
,而OP则需要大约3.5秒。换句话说,我的速度提高了20%。
重要的是要注意两个测试确实产生完全相同的输出。例如,./test-nominalanimal 100000000 | sha256sum -
和./test-antonkretov 100000000 | sha256sum -
都显示完全相同的SHA256校验和7504a1c97167701297c03c4aab8b0f20c5cac82a50128074d6e09c474353d0f8
。
(您也可以将输出保存到文件中,并进行比较;两者的长度都是1,987,777,795字节,并且包含完全相同的数据。我确实检查了。)
如果要运行将数据存储到存储的基准测试,为了使比较公平,您需要从冷存储开始。否则,运行基准测试的顺序将严重影响他们的时间。