Я сейчас сделал тест с кодом ниже (извините, это в cpp).
Код читает текстовый файл размером 5 МБ с количеством потоков, переданных в качестве аргумента командной строки.
Результаты ясно показывают, что несколько потоков всегда ускоряют программу :
Обновление: Мне пришло в голову, что кеширование файлов здесь сыграет свою роль. Поэтому я сделал копии файла testdata, перезагрузил компьютер и использовал разные файлы для каждого запуска. Обновленные результаты ниже (старые в скобках). Вывод остается прежним.
Время выполнения в секундах
Машина A (Dual Quad Core XEON под управлением XP x64 с 4 дисками SAS 10k в RAID 5)
- 1 Тема: 0,61 с (0,61 с)
- 2 темы: 0,44 с (0,43 с)
- 4 Темы: 0,31 с (0,28 с) (Самый быстрый)
- 8 Темы: 0,53 с (0,63 с)
Machine B (двухъядерный ноутбук под управлением XP с одним фрагментированным 2,5-дюймовым диском)
- 1 поток: 0,98 с (1,01 с)
- 2 Темы: 0,67 с (0,61 с) (Самый быстрый)
- 4 темы: 1,78 с (0,63 с)
- 8 Темы: 2,06 с (0,80 с)
Исходный код (Windows):
// FileReadThreads.cpp : Defines the entry point for the console application.
//
#include "Windows.h"
#include "stdio.h"
#include "conio.h"
#include <sys\timeb.h>
#include <io.h>
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int threadCount = 1;
char *fileName = 0;
int fileSize = 0;
double GetSecs(void);
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI FileReadThreadEntry(LPVOID lpThreadParameter)
{ char tx[255];
int index = (int)lpThreadParameter;
FILE *file = fopen(fileName, "rt");
int start = (fileSize / threadCount) * index;
int end = (fileSize / threadCount) * (index + 1);
fseek(file, start, SEEK_SET);
printf("THREAD %4d started: Bytes %d-%d\n", GetCurrentThreadId(), start, end);
for(int i = 0;; i++)
{
if(! fgets(tx, sizeof(tx), file))
break;
if(ftell(file) >= end)
break;
}
fclose(file);
printf("THREAD %4d done\n", GetCurrentThreadId());
return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
if(argc <= 1)
{
printf("Usage: <InputFile> <threadCount>\n");
exit(-1);
}
if(argc > 2)
threadCount = atoi(argv[2]);
fileName = argv[1];
FILE *file = fopen(fileName, "rt");
if(! file)
{
printf("Unable to open %s\n", argv[1]);
exit(-1);
}
fseek(file, 0, SEEK_END);
fileSize = ftell(file);
fclose(file);
printf("Starting to read file %s with %d threads\n", fileName, threadCount);
///////////////////////////////////////////////////////////////////////////
// Start threads
///////////////////////////////////////////////////////////////////////////
double start = GetSecs();
HANDLE mWorkThread[255];
for(int i = 0; i < threadCount; i++)
{
mWorkThread[i] = CreateThread(
NULL,
0,
FileReadThreadEntry,
(LPVOID) i,
0,
NULL);
}
WaitForMultipleObjects(threadCount, mWorkThread, TRUE, INFINITE);
printf("Runtime %.2f Secs\nDone\n", (GetSecs() - start) / 1000.);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
double GetSecs(void)
{
struct timeb timebuffer;
ftime(&timebuffer);
return (double)timebuffer.millitm +
((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
((double)timebuffer.timezone * 60. * 1000.);
}