- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在 32 位 Linux 操作系统上使用 C/C++ 编写代码以从二进制文件中读取无符号整数,该操作系统打算在 8 核 x86 系统上运行。该应用程序采用一个输入文件,该文件包含一个接一个小端格式的无符号整数。因此以字节为单位的输入文件大小是 4 的倍数。文件中可能有十亿个整数。读取和添加所有整数并以 64 位精度返回总和的最快方法是什么?
下面是我的实现。检查损坏数据的错误不是这里的主要问题,在这种情况下,输入文件被认为没有任何问题。
#include <iostream>
#include <fstream>
#include <pthread.h>
#include <string>
#include <string.h>
using namespace std;
string filepath;
unsigned int READBLOCKSIZE = 1024*1024;
unsigned long long nFileLength = 0;
unsigned long long accumulator = 0; // assuming 32 bit OS running on X86-64
unsigned int seekIndex[8] = {};
unsigned int threadBlockSize = 0;
unsigned long long acc[8] = {};
pthread_t thread[8];
void* threadFunc(void* pThreadNum);
//time_t seconds1;
//time_t seconds2;
int main(int argc, char *argv[])
{
if (argc < 2)
{
cout << "Please enter a file path\n";
return -1;
}
//seconds1 = time (NULL);
//cout << "Start Time in seconds since January 1, 1970 -> " << seconds1 << "\n";
string path(argv[1]);
filepath = path;
ifstream ifsReadFile(filepath.c_str(), ifstream::binary); // Create FileStream for the file to be read
if(0 == ifsReadFile.is_open())
{
cout << "Could not find/open input file\n";
return -1;
}
ifsReadFile.seekg (0, ios::end);
nFileLength = ifsReadFile.tellg(); // get file size
ifsReadFile.seekg (0, ios::beg);
if(nFileLength < 16*READBLOCKSIZE)
{
//cout << "Using One Thread\n"; //**
char* readBuf = new char[READBLOCKSIZE];
if(0 == readBuf) return -1;
unsigned int startOffset = 0;
if(nFileLength > READBLOCKSIZE)
{
while(startOffset + READBLOCKSIZE < nFileLength)
{
//ifsReadFile.flush();
ifsReadFile.read(readBuf, READBLOCKSIZE); // At this point ifsReadFile is open
int* num = reinterpret_cast<int*>(readBuf);
for(unsigned int i = 0 ; i < (READBLOCKSIZE/4) ; i++)
{
accumulator += *(num + i);
}
startOffset += READBLOCKSIZE;
}
}
if(nFileLength - (startOffset) > 0)
{
ifsReadFile.read(readBuf, nFileLength - (startOffset));
int* num = reinterpret_cast<int*>(readBuf);
for(unsigned int i = 0 ; i < ((nFileLength - startOffset)/4) ; ++i)
{
accumulator += *(num + i);
}
}
delete[] readBuf; readBuf = 0;
}
else
{
//cout << "Using 8 Threads\n"; //**
unsigned int currthreadnum[8] = {0,1,2,3,4,5,6,7};
if(nFileLength > 200000000) READBLOCKSIZE *= 16; // read larger blocks
//cout << "Read Block Size -> " << READBLOCKSIZE << "\n";
if(nFileLength % 28)
{
threadBlockSize = (nFileLength / 28);
threadBlockSize *= 4;
}
else
{
threadBlockSize = (nFileLength / 7);
}
for(int i = 0; i < 8 ; ++i)
{
seekIndex[i] = i*threadBlockSize;
//cout << seekIndex[i] << "\n";
}
pthread_create(&thread[0], NULL, threadFunc, (void*)(currthreadnum + 0));
pthread_create(&thread[1], NULL, threadFunc, (void*)(currthreadnum + 1));
pthread_create(&thread[2], NULL, threadFunc, (void*)(currthreadnum + 2));
pthread_create(&thread[3], NULL, threadFunc, (void*)(currthreadnum + 3));
pthread_create(&thread[4], NULL, threadFunc, (void*)(currthreadnum + 4));
pthread_create(&thread[5], NULL, threadFunc, (void*)(currthreadnum + 5));
pthread_create(&thread[6], NULL, threadFunc, (void*)(currthreadnum + 6));
pthread_create(&thread[7], NULL, threadFunc, (void*)(currthreadnum + 7));
pthread_join(thread[0], NULL);
pthread_join(thread[1], NULL);
pthread_join(thread[2], NULL);
pthread_join(thread[3], NULL);
pthread_join(thread[4], NULL);
pthread_join(thread[5], NULL);
pthread_join(thread[6], NULL);
pthread_join(thread[7], NULL);
for(int i = 0; i < 8; ++i)
{
accumulator += acc[i];
}
}
//seconds2 = time (NULL);
//cout << "End Time in seconds since January 1, 1970 -> " << seconds2 << "\n";
//cout << "Total time to add " << nFileLength/4 << " integers -> " << seconds2 - seconds1 << " seconds\n";
cout << accumulator << "\n";
return 0;
}
void* threadFunc(void* pThreadNum)
{
unsigned int threadNum = *reinterpret_cast<int*>(pThreadNum);
char* localReadBuf = new char[READBLOCKSIZE];
unsigned int startOffset = seekIndex[threadNum];
ifstream ifs(filepath.c_str(), ifstream::binary); // Create FileStream for the file to be read
if(0 == ifs.is_open())
{
cout << "Could not find/open input file\n";
return 0;
}
ifs.seekg (startOffset, ios::beg); // Seek to the correct offset for this thread
acc[threadNum] = 0;
unsigned int endOffset = startOffset + threadBlockSize;
if(endOffset > nFileLength) endOffset = nFileLength; // for last thread
//cout << threadNum << "-" << startOffset << "-" << endOffset << "\n";
if((endOffset - startOffset) > READBLOCKSIZE)
{
while(startOffset + READBLOCKSIZE < endOffset)
{
ifs.read(localReadBuf, READBLOCKSIZE); // At this point ifs is open
int* num = reinterpret_cast<int*>(localReadBuf);
for(unsigned int i = 0 ; i < (READBLOCKSIZE/4) ; i++)
{
acc[threadNum] += *(num + i);
}
startOffset += READBLOCKSIZE;
}
}
if(endOffset - startOffset > 0)
{
ifs.read(localReadBuf, endOffset - startOffset);
int* num = reinterpret_cast<int*>(localReadBuf);
for(unsigned int i = 0 ; i < ((endOffset - startOffset)/4) ; ++i)
{
acc[threadNum] += *(num + i);
}
}
//cout << "Thread " << threadNum + 1 << " subsum = " << acc[threadNum] << "\n"; //**
delete[] localReadBuf; localReadBuf = 0;
return 0;
}
我编写了一个小的 C# 程序来生成用于测试的输入二进制文件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace BinaryNumWriter
{
class Program
{
static UInt64 total = 0;
static void Main(string[] args)
{
BinaryWriter bw = new BinaryWriter(File.Open("test.txt", FileMode.Create));
Random rn = new Random();
for (UInt32 i = 1; i <= 500000000; ++i)
{
UInt32 num = (UInt32)rn.Next(0, 0xffff);
bw.Write(num);
total += num;
}
bw.Flush();
bw.Close();
}
}
}
在具有 2 GB RAM 和 Ubuntu 9.10 32 位的 Core i5 机器上运行该程序 @ 3.33 Ghz(它是四核,但它是我目前得到的)具有以下性能数字
100 个整数 ~ 0 秒(否则我真的很糟糕)100000 个整数 < 0 秒100000000 个整数~ 7 秒500000000 个整数 ~ 29 秒(1.86 GB 输入文件)
我不确定硬盘是 5400RPM 还是 7200RPM。我尝试了不同的缓冲区大小来读取,发现一次读取 16 MB 的大输入文件是一个最佳选择。
有没有更好的方法可以更快地读取文件以提高整体性能?有没有更聪明的方法来更快地添加大型整数数组并重复折叠?我编写代码的方式是否存在性能方面的主要障碍/我是否在做一些明显错误的事情并花费大量时间?
我可以做些什么来加快这个读取和添加数据的过程?
谢谢。
金梅
最佳答案
以您的方式从多线程访问机械 HDD 将需要一些头部运动(阅读慢下来)。您几乎可以肯定是 IO 限制(1.86GB 文件为 65MBps)。尝试通过以下方式改变您的策略:
你需要相当多的同步才能让它完美地工作,我认为它会通过顺序文件访问来完全发挥你的 HDD/文件系统 IO 能力。 YMMV 上的小文件,可以缓存并以闪电般的速度从缓存中提供。
您可以尝试的另一件事是只启动 7 个线程,为主线程和系统的其余部分留出一个空闲 CPU。
.. 或者买一个 SSD :)
编辑:
为简单起见,看看在没有任何处理的情况下单线程读取文件(丢弃缓冲区)的速度有多快。这加上 epsilon 是您完成此操作的速度的理论极限。
关于c++ - 在 C/C++ 中快速读取然后从二进制文件中添加大量整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10953210/
如何更改循环中变量的名称?比如 number1 、 number2 、 number3 、 number4 ? var array = [2,4,6,8] func ap ( number1: Int
我想设置 View 的背景颜色并在一定延迟后将其更改为另一种颜色。这是我的尝试方式: print("setting color 1") self.view.backgroundColor = UICo
我在使用 express-session 时遇到问题。 session 数据不会在请求之间持续存在。 正如您在下面的代码中看到的那样,/join 路由设置了一些 session 属性,但是当 /sur
我试图从叶渲染器获得一个非常简单的结果,用于快速 Steam 的 for 循环。 我正在上传叶文件 HTML,因为它不接受此处格式正确的代码 - 下面的pizza.swift代码- import
你们中有人有什么好的链接可以与我分享吗?我正在寻找一个 FAST 程序员编辑器,它可以非常快速地打开包含超过 100, 000 行代码的文件?我目前正在使用记事本自动取款机,打开一个 29000 行长
我现在正在处理眼动追踪数据,因此拥有一个巨大的数据集(想想数百万行),因此希望有一种快速的方法来完成此任务。这是它的简化版本。 数据告诉您眼睛在每个时间点正在查看的位置以及我们正在查看的每个文件。 X
我是新手,想为计时器或其他设备选择提示音。 如何打开此列表,以选择其中一种声音? Alert sound list 最佳答案 您将无法在应用中使用系统声音。 但是,您可以包括自己的声音文件,并将其显示
我编写了以下代码来构建具有顺序字符串的数组。 它的工作方式与我预期的一样,但我希望它能更快地运行。有没有更有效的方法在PowerShell中产生我想要的结果? 我是PowerShell的新手,非常感谢
我有一个包含一些非唯一行的矩阵,例如: x 尝试 y <- rle(apply(x, 1, paste, collapse = " ")) # y$lengths is the vector con
我的函数“keyboardWillShown”有问题。所以我想要的是菜单打开时,菜单正好出现在键盘上方。它可以在Iphone 8 plus,8、7、6上完美运行。但是,当我在模拟器上运行Iphone
我正在尝试通过Swift 5中的HTTP get方法从API提取数据。它在启动时成功加载了数据,但是当我刷新页面时,它说“索引超出范围”,这是因为数据是不再会在我的日志中读取,因此索引中没有任何内容。
我想做什么: 从我的数据库中获取时间戳并将其转换为用户的时区。 我的代码: let tryItNow = "\(model.timestampName)" let format = D
给定字体名称和字体大小,如何查找字符串的宽度(CGFloat)? (目标是将UIView的宽度设置为足以容纳字符串的宽度。) 我有两个字符串:一个重复“1”,重复36次,另一个重复“M”,重复36次。
我正在尝试解析此JSON ["Items": ( { AccountBalance = 0; AlphabetType = 3; Description = "\U0631\U
我在UINavigationBar内放置了一个UILabel。 我想根据navigationBar的高度增加该标签的字体大小。当navigationBar很大时,我希望字体大小更大;当滚动并缩小nav
我想将用户输入限制为仅有效数字并使用以下内容: func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, rep
目前我有一个包含超过 100.000 张图像的数据库,它们大小不一或类似,但我想为我的公司制作以下内容: 我插入/上传一张图片,系统返回最有可能相同的图片。我不知道使用什么算法,但它需要快速。我可以预
在我的 swift 项目中,我有一个按钮,我想在标签上打印按下该按钮的时间。 如何解决这个问题? 最佳答案 添加到DHEERAJ的答案中,您只需在func press(sender: UIButton
我必须发表评论,尝试在解析中导入数组。然而,有一个问题。 当我尝试从 Parse 加载数组时,我的输出是 ("Blah","Blah","Blah")这是一个元组...而不是一个数组 TT... 如何
我的应用程序有一个名为 MyDevice 的类,我用它来与硬件通信。该硬件是可选的,实例变量也是可选的: var theDevice:MyDevice = nil 然后,在应用程序中,我必须初始化设备
我是一名优秀的程序员,十分优秀!