关于使用FileMapping和直接操作File+缓存的IO性能对比

博客探讨了在Windows核心编程中使用FileMapping与直接操作File+缓存的IO性能差异。通过关闭可能产生IO干扰的进程进行测试,发现多线程下FileMapping在某些情况下能提升性能。此外,还计划在开启干扰软件的环境下进行补充测试。
摘要由CSDN通过智能技术生成

最近在看Windows核心编程17章

作者推崇使用FileMapping来进行大文件读写。虽然这样可以直接把文件映射到进程地址空间,由操作系统来进行后备的换成,换页等复杂操作。程序员只需要直接把文件当做内存地址来操作即可。

可是笔者发现这可能对于编码来说相对简单了,可是把缓存这些全交给操作系统来处理并不是一个好的方法。尤其在处理大文件IO的时候。于是笔者对原书上的一个例子进行了改写对比。首先这是改写后的代码。此代码当然也支持原书本上的逻辑。


完整代码:


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <iostream>


//
class CStopwatch {
public:
	CStopwatch() { QueryPerformanceFrequency(&m_liPerfFreq); Start(); }

	void Start() { QueryPerformanceCounter(&m_liPerfStart); }

	__int64 Now() const { // Returns # of millisecond since Start was called
		LARGE_INTEGER liPerfNow;
		QueryPerformanceCounter(&liPerfNow);
		return(((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000)
			/ m_liPerfFreq.QuadPart);
	}

	__int64 NowInMicro() const { // Return # of microseconds
		// since Start was called
		LARGE_INTEGER liPerfNow;
		QueryPerformanceCounter(&liPerfNow);
		return(((liPerfNow.QuadPart - m_liPerfStart.QuadPart) * 1000000)
			/ m_liPerfFreq.QuadPart);
	}


private:
	LARGE_INTEGER m_liPerfFreq;	// Counts per second
	LARGE_INTEGER m_liPerfStart; // Starting count
};

CStopwatch stopwatch;
//

typedef struct {
	PVOID pvAddr;
	DWORD dwBlockSize;
	DWORD dwCount;
	bool bIsFinished;
} WORK_DATA, *PWORK_DATA;


typedef struct {
	WORK_DATA wDATA;
	PTP_WORK pWork;
} WORKITEM_INFO, *PWORKITEM_INFO;

#define MAX_THREADS	4
PWORKITEM_INFO  g_WORKITEM[MAX_THREADS] = { 0 };
PBYTE		g_BUFF[MAX_THREADS] = { 0 };

HANDLE hSemp = NULL;
//

VOID CALLBACK WorkCallback(
	PTP_CALLBACK_INSTANCE Instance,
	PVOID Context,
	PTP_WORK Work) {

	PWORK_DATA pData = (PWORK_DATA)Context;

	// Count the number of 0s in this block.
	PBYTE pFile = (PBYTE)pData->pvAddr;
	for (DWORD dwByte = 0; dwByte < pData->dwBlockSize; dwByte++) {
		if (pFile[dwByte] == 0)
			pData->dwCount++;
	}
	pData->bIsFinished = true;

	ReleaseSemaphoreWhenCallbackReturns(Instance, hSemp, 1);
}


__int64 CountWithFileMapMultiThreads(HANDLE hFileMap, __int64 qwFileSize, DWORD dwBlockSize, DWORD nThreads) {

	if (nThreads > MAX_THREADS)
		return -1;		// invalid threads count.

	ZeroMemory(g_WORKITEM, sizeof(PTP_WORK) * nThreads);

	__int64 qwFileOffset = 0, qwNumOfZeros = 0;

	hSemp = CreateSemaphore(NULL, nThreads, nThreads, NULL);

	// allocate the buff.
	for (unsigned int i = 0; i < nThreads; i++) {
		g_WORKITEM[i] = (PWORKITEM_INFO)malloc(sizeof(WORKITEM_INFO));
		g_WORKITEM[i]->wDATA.bIsFinished = true;
		g_WORKITEM[i]->pWork = NULL;
		g_WORKITEM[i]->wDATA.pvAddr = NULL;
	}


	while (qwFileSize > 0) {
		WaitForSingleObject(hSemp, INFINITE);	// wait for a resource.
		// do some resource clean up.
		for (unsigned int i = 0; i < nThreads; i++) {
			if (g_WORKITEM[i]) {	// there is a working item.
				if (g_WORKITEM[i]->wDATA.bIsFinished && g_WORKITEM[i]->pWork) { // this item has been finished
					// get the data.
					qwNumOfZeros += g_WORKITEM[i]->wDATA.dwCount;

					// Unmap the file.
					UnmapViewOfFile(g_WORKITEM[i]->wDATA.pvAddr);

					// close the work item.
					CloseThreadpoolWork(g_WORKITEM[i]->pWork);

					g_WORKITEM[i]->pWork = NULL;
				}
			}
		}

		// get a free slot
		unsigned int nSlotID;
		for (nSlotID = 0; nSlotID < nThreads; nSlotID++) {
			if (g_WORKITEM[nSlotID]->pWork == NULL)	// get a free slot.
				break;
		}
		// there is a thread available.
		if (nSlotID < nThreads)
		{
			// Determine the number of bytes to be mapped in this view
			DWORD dwBytesInBlo
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您想了解如何从Filemapping中读取数据并使用CreateFile函数写入文件。首先,需要使用CreateFileMapping函数创建一个文件映射对象,将文件映射到进程的地址空间中。然后使用MapViewOfFile函数将文件映射到进程的地址空间中并返回指向该区域的指针。接下来,您可以使用指针访问文件映射中的数据。最后,使用CreateFile函数创建一个新文件或打开已存在的文件,并使用WriteFile函数将数据写入该文件。 以下是一个简单的示例代码,展示如何实现从Filemapping中读取数据并使用CreateFile函数写入文件: ``` HANDLE hFile = CreateFile("output.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { printf("Error creating file. Error code: %d\n", GetLastError()); return; } HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, "MyFileMap"); if (hMapFile == NULL) { printf("Error creating file mapping. Error code: %d\n", GetLastError()); CloseHandle(hFile); return; } LPVOID lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 1024); if (lpMapAddress == NULL) { printf("Error mapping view of file. Error code: %d\n", GetLastError()); CloseHandle(hMapFile); CloseHandle(hFile); return; } DWORD dwBytesWritten; if (!WriteFile(hFile, lpMapAddress, 1024, &dwBytesWritten, NULL)) { printf("Error writing file. Error code: %d\n", GetLastError()); } UnmapViewOfFile(lpMapAddress); CloseHandle(hMapFile); CloseHandle(hFile); ``` 注意:此示例代码仅供参考,您需要根据自己的需求进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值