C++ 我为班级写了这个汉明编码。为什么这么慢?
我为我的操作系统类写了以下内容:C++ 我为班级写了这个汉明编码。为什么这么慢?,c++,file,operating-system,hamming-code,C++,File,Operating System,Hamming Code,我为我的操作系统类写了以下内容: #include <iostream> #include <fstream> //encodes a file using the (8,4) Hamming Code. //usage : HammingEncode.out < inputFile > outputFile int main() { unsigned char const codebook[] = {0x00, 0x1E, 0x2D, 0x33,
#include <iostream>
#include <fstream>
//encodes a file using the (8,4) Hamming Code.
//usage : HammingEncode.out < inputFile > outputFile
int main() {
unsigned char const codebook[] = {0x00, 0x1E, 0x2D, 0x33, 0x4B, 0x55, 0x66, 0x78, 0x87, 0x99, 0xAA, 0xB4, 0xCC, 0xD2, 0xE1, 0xFF};
unsigned char in, nextByte;
unsigned char const leftMask = 0xF0, rightMask = 0x0F;
in = std::cin.get();
while (!std::cin.eof()) {
nextByte = (in & leftMask) >> 4;
std::cout << codebook[nextByte];
nextByte = in & rightMask;
std::cout << codebook[nextByte];
in = std::cin.get();
}
}
#包括
#包括
//使用(8,4)汉明码对文件进行编码。
//用法:hammingecode.outoutputFile
int main(){
无符号字符常量码本[]={0x00、0x1E、0x2D、0x33、0x4B、0x55、0x66、0x78、0x87、0x99、0xAA、0xB4、0xCC、0xD2、0xE1、0xFF};
未签名字符输入,下一字节;
无符号字符常量leftMask=0xF0,rightMask=0x0F;
in=std::cin.get();
而(!std::cin.eof()){
nextByte=(in&leftMask)>>4;
std::cout若我理解正确,对于读取的每个字节,您将写入2个字节。所以输出文件的大小将是输入的两倍。若您的输入足够大,则总IO(读取+2*写入)时间将非常重要
在哈夫曼编码中,情况并非如此——因为您通常写的比读的少,并且总IO时间要少得多
编辑:
正如Blorgbeard所说,它可以是缓冲的区别。C++也可以缓冲,但默认缓冲区要比java小很多,而且HDD头应该在一个位置读文件,然后在另一个位置上写入,这会显著影响整个IO性能。
在任何情况下,编码都应该分块进行,以确保大数据块的顺序读写C++iostream被认为效率很低,尽管不同的数字表明这是实现质量问题,而不是iostream的缺点
无论如何,只是为了确保它不是慢硬盘,你可以比较执行时间,例如
cat file1 > file2
当然,courcecat
会更快一些,因为它不会使数据的大小增加一倍
然后尝试将代码的效率与以下内容进行比较:
#include <stdio.h>
#include <unistd.h>
int main()
{
unsigned char buffer[1024*1024]; // 1MB buffer should be enough
while (!eof(STDIN_FILENO)){
size_t len = read(STDIN_FILENO, &buffer[0], 1024*1024);
write(STDOUT_FILENO, &buffer[0], len);
write(STDOUT_FILENO, &buffer[0], len);
}
return 0;
}
#包括
#包括
int main()
{
无符号字符缓冲区[1024*1024];//1MB缓冲区应该足够了
而(!eof(标准文件号)){
size\u t len=read(标准文件号和缓冲区[0],1024*1024);
写入(标准输出文件号和缓冲区[0],len);
写入(标准输出文件号和缓冲区[0],len);
}
返回0;
}
编辑:
对不起,我的错。试试看
#include <stdio.h>
#include <unistd.h>
int main()
{
unsigned char buffer[1024*1024]; // 1MB buffer should be enough
size_t len = read(STDIN_FILENO, &buffer[0], 1024*1024);
while(len > 0){
write(STDOUT_FILENO, &buffer[0], len);
write(STDOUT_FILENO, &buffer[0], len);
len = read(STDIN_FILENO, &buffer[0], 1024*1024);
}
return 0;
}
#包括
#包括
int main()
{
无符号字符缓冲区[1024*1024];//1MB缓冲区应该足够了
size\u t len=read(标准文件号和缓冲区[0],1024*1024);
而(len>0){
写入(标准输出文件号和缓冲区[0],len);
写入(标准输出文件号和缓冲区[0],len);
len=read(标准文件号和缓冲区[0],1024*1024);
}
返回0;
}
std::cin
是以文本模式打开的,因此它一直在寻找各种需要注意的东西(如换行符等)
考虑到std::cin
输入流不断地进行字符嗅探,我并不惊讶它需要更长的时间,但它似乎有点过度。下面,绕过iostream
并直接使用FILE
流可能会达到您所期望的效果:
#include <cstdlib>
#include <cstdio>
int main(int argc, char *argv[])
{
static unsigned char const codebook[] =
{
0x00, 0x1E, 0x2D, 0x33, 0x4B, 0x55, 0x66, 0x78,
0x87, 0x99, 0xAA, 0xB4, 0xCC, 0xD2, 0xE1, 0xFF
};
for (int c = std::fgetc(stdin); c!=EOF; c=std::fgetc(stdin))
{
std::fputc(codebook[c >> 4], stdout);
std::fputc(codebook[c & 0x0F], stdout);
}
return EXIT_SUCCESS;
}
使用std::cin
和std::cout
time ./hamming < bigfile.txt > bigfile.ham
real 0m23.819s
user 0m7.416s
sys 0m16.377s
time ./hamming < bigfile.txt > bigfile.ham
real 0m24.867s
user 0m7.705s
sys 0m17.118s
总而言之,哎哟。值得注意的是在系统中花费的时间。如果我有机会用std::istream::get()
和put()
方法来更新这个,我会的,但老实说,我不希望在这方面有任何奇迹。除非有魔法(对我,而不是对其他人)从std::cin
文件流关闭io xlat的方法可能是一个合理的选择。我还没有研究slurpingstd::cin
的rdbuf()
是否是一个可行的选择,但它也可能有希望
编辑:使用std::istreambuf\u迭代器
time ./hamming < bigfile.txt > bigfile.ham
real 0m23.819s
user 0m7.416s
sys 0m16.377s
time ./hamming < bigfile.txt > bigfile.ham
real 0m24.867s
user 0m7.705s
sys 0m17.118s
使用streambuf迭代器类有显著的改进,因为它基本上绕过了所有内联slat垃圾,但它仍然不如文件
流那样有效:
#include <iostream>
#include <cstdlib>
#include <cstdio>
int main(int argc, char *argv[])
{
static unsigned char const codebook[] =
{
0x00, 0x1E, 0x2D, 0x33, 0x4B, 0x55, 0x66, 0x78,
0x87, 0x99, 0xAA, 0xB4, 0xCC, 0xD2, 0xE1, 0xFF
};
std::istreambuf_iterator<char> cin_it(std::cin), cin_eof;
std::for_each(cin_it, cin_eof, [](char c)
{
std::cout.put(static_cast<char>(codebook[static_cast<unsigned char>(c) >> 4]));
std::cout.put(static_cast<char>(codebook[static_cast<unsigned char>(c) & 0x0F]));
});
return EXIT_SUCCESS;
}
正如你所料,结果是可怕的:
time ./hamming < bigfile.txt > bigfile.ham
real 0m26.509s
user 0m2.370s
sys 0m24.087s
time./hammingbigfile.ham
真正的0m26.509s
用户0m2.370s
系统0m24.087s
我做了两个小改动,几乎提高了一个数量级
添加std::ios\u base::synch\u与\u stdio(false)
(没有明显区别,尽管影响通常是特定于实现的)
在写入之前缓冲输出(这产生了最大的差异)
更新后的代码如下所示:
int main()
{
//encodes a file using the (8,4) Hamming Code.
//usage : HammingEncode.out < inputFile > outputFile
unsigned char const codebook[] = { 0x00, 0x1E, 0x2D, 0x33, 0x4B, 0x55, 0x66, 0x78, 0x87, 0x99, 0xAA, 0xB4, 0xCC, 0xD2, 0xE1, 0xFF };
unsigned char in, nextByte;
unsigned char const leftMask = 0xF0, rightMask = 0x0F;
std::stringstream os;
std::ios_base::sync_with_stdio(false);
in = std::cin.get();
while (std::cin) {
nextByte = (in & leftMask) >> 4;
os.put(codebook[nextByte]);
nextByte = in & rightMask;
os.put(codebook[nextByte]);
in = std::cin.get();
}
std::cout << os.rdbuf();
}
嗯,是的。但是我不明白为什么写一个文件要比直接用Java写一个文件花两倍的时间。比如说,如果我用Java写两次这个文件,速度会快得多。所以我想知道为什么这段代码要花30秒来写8MB的8MB的8MB的30秒听起来确实很慢。我会尝试实验:试着只读一读一个字节接一个字节的文件,对于每个字节,只需将读取的字节写入输出文件两次。这样可以了解问题是在IO中还是在算法本身(不太可能)。但重要的是读取字节,然后立即写入两次(不要读取缓冲区,然后写入缓冲区两次)@DenisItskovitch我不确定我是否知道如何在不使用iostream的情况下直接写,iostream是缓冲区。我不能做nextByte=std::cin.get()&rightMask;std::cout@JonCohen我不是指直接写。我的意思是像你在问题中所做的那样读/写,但没有编码尝试,所用的时间也一样长:(很可能是java在为您缓冲输入和输出。您在这里一次读取/写入一个字节。@Blorgbeard iostream也在缓冲。@j_kubik我可以更正。您的编译标志是什么?在这种情况下,未优化的代码会非常慢,但优化有可能将其加速几个数量级。@j_kubik g++HammingCode.cpp-O2-o HammingCode.out这不编译,它不识别eof。我用feof替换了它并编译了它,但给了我一个segfault。static\u cast(c)
是多余的;定义了fgetc
函数
int main()
{
//encodes a file using the (8,4) Hamming Code.
//usage : HammingEncode.out < inputFile > outputFile
unsigned char const codebook[] = { 0x00, 0x1E, 0x2D, 0x33, 0x4B, 0x55, 0x66, 0x78, 0x87, 0x99, 0xAA, 0xB4, 0xCC, 0xD2, 0xE1, 0xFF };
unsigned char in, nextByte;
unsigned char const leftMask = 0xF0, rightMask = 0x0F;
std::stringstream os;
std::ios_base::sync_with_stdio(false);
in = std::cin.get();
while (std::cin) {
nextByte = (in & leftMask) >> 4;
os.put(codebook[nextByte]);
nextByte = in & rightMask;
os.put(codebook[nextByte]);
in = std::cin.get();
}
std::cout << os.rdbuf();
}
int main()
{
//encodes a file using the (8,4) Hamming Code.
//usage : HammingEncode.out < inputFile > outputFile
unsigned char const codebook[] = { 0x00, 0x1E, 0x2D, 0x33, 0x4B, 0x55, 0x66, 0x78, 0x87, 0x99, 0xAA, 0xB4, 0xCC, 0xD2, 0xE1, 0xFF };
unsigned char in, nextByte;
unsigned char const leftMask = 0xF0, rightMask = 0x0F;
std::stringstream os;
std::ios_base::sync_with_stdio(false);
std::streambuf * pbuf = std::cin.rdbuf();
do {
in = pbuf->sgetc();
nextByte = (in & leftMask) >> 4;
os << codebook[nextByte];
nextByte = in & rightMask;
os << codebook[nextByte];
} while (pbuf->snextc() != EOF);
std::cout << os.rdbuf();
}