Форум: "WinAPI";
Текущий архив: 2009.05.24;
Скачать: [xml.tar.bz2];
ВнизReadFile c Overlapped, ньюансы работы. Найти похожие ветки
← →
MetalFan © (2007-12-16 19:46) [0]решил разобраться с вызовом функций WinApi в асинхронном режиме.
покурил msdn, накидал такой примерчик:
procedure TForm1.DoAsyncLoad();
var
lReaded: Cardinal;
lTransferred: Cardinal;
lBuff: Pointer;
lRes: Boolean;
lErr, lErr2: Cardinal;
lFileHandle: Cardinal;
lOverlapped: TOverlapped;
begin
lFileHandle := CreateFile( PChar( edtFileName.Text ),
GENERIC_READ, 0,
nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0 );
if lFileHandle = INVALID_HANDLE_VALUE then
RaiseLastOSError;
try
lReaded := 0;
ZeroMemory( @lOverlapped, SizeOf( TOverlapped ));
GetMem( lBuff, C_BLOCK_SIZE ); //используем большой буфер
try
repeat
lReaded := 0;
//обнуляем внутренние данные для нового вызова "перекрываемой" функции
lOverlapped.Internal := 0;
lOverlapped.InternalHigh := 0;
//hEvent не задаю, так как нигде ожидать ничего не будем
lRes := ReadFile( lFileHandle,
lBuff^,
C_BLOCK_SIZE,
lReaded,
@lOverlapped );
if not lRes then
lErr := GetLastError
else
lErr := ERROR_SUCCESS;
if not lRes then
case lErr of //проверка ощибки ReadFile
ERROR_IO_PENDING: //асинхронная операция
begin
lTransferred := 0;
repeat
lRes := GetOverlappedResult( lFileHandle,
lOverlapped,
lTransferred,
False );
if not lRes then
lErr2 := GetLastError;
if not lRes then
case lErr2 of //проверка ошибки GetOverlappedResult
ERROR_IO_INCOMPLETE: Application.HandleMessage; //операция не завершилась? обработаем очередное сообщение
ERROR_HANDLE_EOF:
begin //файл кончился?
lReaded := 0; //ничего не прочитали
break; //выходим из внутреннего цикла
end;
else
RaiseLastOSError;
end;
until lRes; //пока не завершиться операция...
if lRes then
lReaded := lTransferred; //надо ли?
end;
ERROR_HANDLE_EOF: lReaded := 0; //если файл кончилсо, то выходим из цикла
else
RaiseLastOSError;
end;
if lRes then
begin
//
//что-то делаем с lBuff
//
lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем
end;
until lReaded = 0;
finally
FreeMem( lBuff );
end;
finally
CloseHandle( lFileHandle );
end;
end;
все бы ничего... да только не всегда получается асинхронный вызов.
в случае попытки чтения большого файла с винчестера функция FileRead ждет окончания чтения и возвращает true (
и только в случае первой попытки обращения к съемному носителю срабатывает часть кода по работе с GetOverlappedResult...
объясните знающие люди, в чем соль?!
← →
Riply © (2007-12-16 19:49) [1]После того как FileRead вернет True,
надо вызвать GetLastError, чтобы узнать причину удачи :)
← →
MetalFan © (2007-12-16 19:57) [2]
> Riply © (16.12.07 19:49) [1]
:-P
← →
DiamondShark © (2007-12-17 14:02) [3]
> else
> RaiseLastOSError;
Это после вызова GetLastError?
> lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем
а это зачем?! 8-(
А чего б тебе не юзать синхронные вызовы в отдельном потоке?
Код намного менее макаронистый получится.
← →
Игорь Шевченко © (2007-12-17 14:03) [4]а вот пример в http://www.delphimaster.ru/articles/named_pipes/index.html
пользует асинхронный воод-вывод аккурат на API и вроде как работает...
← →
DiamondShark © (2007-12-17 14:19) [5]
> в случае попытки чтения большого файла с винчестера функция
> FileRead ждет окончания чтения и возвращает true
Большой там файл, или не большой -- до лампочки, ты всё равно C_BLOCK_SIZE байт за раз читаешь.
Если эта константа имеет весьма скромное значение, то вполне рациональна стратегия системы считать эти байты с быстрого устройства, не заморачиваясь на сомнительной выгоды асинхронность.
← →
tesseract © (2007-12-17 14:22) [6]
> не заморачиваясь на сомнительной выгоды асинхронность.
Загрузка процессора программой ниже.
← →
MetalFan © (2007-12-17 15:04) [7]
> > lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем
>
> а это зачем?! 8-(
как зачем? при асинхронном обращении необходимо указать, с какого места чтение осуществляется.
MSDN
Offset
File position at which to start the transfer. The file position is a byte offset from the start of the file. The calling process must set this member before calling the ReadFile or WriteFile function.
This member is used only when the device is a file. Otherwise, this member must be zero.
> А чего б тебе не юзать синхронные вызовы в отдельном потоке?
>
> Код намного менее макаронистый получится.
для этого надо городить отдельный поток. а если у меня будет 500 файлов читаться?
> Большой там файл, или не большой -- до лампочки, ты всё
> равно C_BLOCK_SIZE байт за раз читаешь.
C_BLOCK_SIZE = 50 * 1024 * 1024;
забыл указать.
> Игорь Шевченко © (17.12.07 14:03) [4]
нет, тут работа с файловой системой, а не с трубками.
в общем после ряда экспериментов выяснилось:
1. ReadFile возвр.True после небольшой задержки в случае обращения к файлу на винте.
2. ReadFile сразу же возвр.False в случае обращения к файлу на сменном носителе или в сети.
читать пытаюсь файлы >200Mb с буфером >10Mb.
← →
DiamondShark © (2007-12-17 15:35) [8]
> для этого надо городить отдельный поток.
По сравнению с этим огородом, горожение отдельного потока -- тьфу и растереть.
> а если у меня будет 500 файлов читаться?
То тебе по-любому боглах будет.
Во-первых, 500 буферов по 50 Мб нигде не поместятся.
Во-вторых, код диспетчеризации нескольких асинхронных файлов будет сложнее, чем код простого потока синхронного в/в.
А в-третьих, 500 файлов у тебя всё равно никогда не будет, это ты для красного словца сказал. Если они >200Mb, то в память они всё равно не поместятся, так что обрабатывать их придётся всё равно друг за другом.
> 1. ReadFile возвр.True после небольшой задержки в случае
> обращения к файлу на винте.
> 2. ReadFile сразу же возвр.False в случае обращения к файлу
> на сменном носителе или в сети.
И правильно делает.
Считать с ЖД в память 50 Мб -- дело долей секунды.
← →
tesseract © (2007-12-17 15:55) [9]
> для этого надо городить отдельный поток. а если у меня будет
> 500 файлов читаться?
Одновременно ? Разница при любом подходе будет малозначительной, винда повиснет наглухо :-)
← →
MetalFan © (2007-12-17 15:56) [10]
> И правильно делает.
> Считать с ЖД в память 50 Мб -- дело долей секунды.
тоже верно...
видимо основную задержку при вызове ReadFile создает копирование памяти...
← →
Alex Konshin © (2007-12-26 00:33) [11]А зачем вообще читать десятки мегабайт в память?
Нужно просто мапить этот файл на память и всё. Никаких проблем.
Работу с файлом оформить в отдельный поток.
← →
J_f_S (2007-12-26 10:30) [12]
> Нужно просто мапить этот файл на память и всё. Никаких проблем.
>
> Работу с файлом оформить в отдельный поток.
+1
← →
MetalFan © (2007-12-26 19:37) [13]собстно это было мое исследование(попытки) работы с overlapped.
всем спасибо за участие!
← →
Eraser © (2007-12-26 21:18) [14]учитывая рост количества ядер в процах, имеет смысл ориентироваться на синхронную архитектуру, а не наоборот.
← →
MetalFan © (2007-12-26 23:24) [15]а почему?
← →
Eraser © (2007-12-26 23:59) [16]потому что при увеличении числа ядер/процессоров уменьшаются накладные расходы на переключение контекстов потоков, не говоря уже об общем повышении производительности.
← →
MetalFan © (2007-12-27 09:00) [17]а разве утверждение, что "оптимальное кол-во потоков равно числу ядер/процессоров" неверно?
← →
Alex Konshin © (2007-12-27 10:38) [18]Неверно в корне.
Во-первых, есть ещё такая штука как гипертрединг (который обещают вернуть в следующих поколениях многоядерников).
Во-вторых, есть и другие (и системные в том числе) процессы со своими потоками.
В-третьих, ваши потоки когда-нибудь будут ждать.
...
А есть ещё и в-пятых, и в-двадцатых...
← →
Alex Konshin © (2007-12-27 10:48) [19]> Eraser © (26.12.07 21:18) [14]
> учитывая рост количества ядер в процах, имеет смысл ориентироваться
> на синхронную архитектуру, а не наоборот.
Не вижу логики. Что ты называешь синхронной архитектурой?
Наоборот, сейчас имеет смысл распараллеливать всё что можно, то есть всё делать асинхронно. И чем дальше, тем это становится более актуально. Например, в ближайшие пару лет появятся 8-ми ядерные процессоры, а на них может быть гипертрединг, тогда чем сильнее распараллелишь, тем быстрее будет работать (там где это имеет смысл, естественно). Кстати, Delphi в этом плохой помошник, точнее вообще никакой, и никаких намёков на улучшение ситуации.
← →
Eraser © (2007-12-27 12:27) [20]
> Alex Konshin © (27.12.07 10:48) [19]
> Что ты называешь синхронной архитектурой?
В данном случае я имею ввиду архитекуру, при которой для каждого соединения создается отдельный поток.
асинхронная арихеткура как раз подразумевает то, что достаточно всего одного потока для работы со множеством соединений, в ряде случаев это дейтсивительно дает приемущество, но учитывая [14] подход будет меняться, тем более что с т.з. программиста организоваться синхронную передачу данных куда проще. Насчет распараллеливания полностью согласен, через несколько лет появятся встроенные языковые средства для поддержки многопоточности.
← →
MetalFan © (2007-12-27 17:21) [21]
> через несколько лет появятся встроенные языковые средства
> для поддержки многопоточности
какие такие средства? а TThread - это не средство?
← →
Eraser © (2007-12-27 17:37) [22]
> MetalFan © (27.12.07 17:21) [21]
нет, TThread это не языковое средство поддержки многопоточности..
единственное языковое средство в Делфи, связанное с многопоточностью приходит на ум только ThreadVar.
← →
MetalFan © (2007-12-27 18:25) [23]
> Eraser © (27.12.07 17:37) [22]
понял. спасибо)
← →
имя (2008-05-08 10:43) [24]Удалено модератором
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2009.05.24;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.006 c