-
решил разобраться с вызовом функций 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;
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 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 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
lOverlapped.Offset := lOverlapped.Offset + lReaded; end;
until lReaded = 0;
finally
FreeMem( lBuff );
end;
finally
CloseHandle( lFileHandle );
end;
end;
все бы ничего... да только не всегда получается асинхронный вызов. в случае попытки чтения большого файла с винчестера функция FileRead ждет окончания чтения и возвращает true ( и только в случае первой попытки обращения к съемному носителю срабатывает часть кода по работе с GetOverlappedResult... объясните знающие люди, в чем соль?!
-
После того как FileRead вернет True, надо вызвать GetLastError, чтобы узнать причину удачи :)
-
> Riply © (16.12.07 19:49) [1]
:-P
-
> else > RaiseLastOSError;
Это после вызова GetLastError?
> lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем
а это зачем?! 8-(
А чего б тебе не юзать синхронные вызовы в отдельном потоке? Код намного менее макаронистый получится.
-
-
> в случае попытки чтения большого файла с винчестера функция > FileRead ждет окончания чтения и возвращает true
Большой там файл, или не большой -- до лампочки, ты всё равно C_BLOCK_SIZE байт за раз читаешь.
Если эта константа имеет весьма скромное значение, то вполне рациональна стратегия системы считать эти байты с быстрого устройства, не заморачиваясь на сомнительной выгоды асинхронность.
-
> не заморачиваясь на сомнительной выгоды асинхронность.
Загрузка процессора программой ниже.
-
> > 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.
-
> для этого надо городить отдельный поток.
По сравнению с этим огородом, горожение отдельного потока -- тьфу и растереть.
> а если у меня будет 500 файлов читаться?
То тебе по-любому боглах будет. Во-первых, 500 буферов по 50 Мб нигде не поместятся. Во-вторых, код диспетчеризации нескольких асинхронных файлов будет сложнее, чем код простого потока синхронного в/в. А в-третьих, 500 файлов у тебя всё равно никогда не будет, это ты для красного словца сказал. Если они >200Mb, то в память они всё равно не поместятся, так что обрабатывать их придётся всё равно друг за другом.
> 1. ReadFile возвр.True после небольшой задержки в случае > обращения к файлу на винте. > 2. ReadFile сразу же возвр.False в случае обращения к файлу > на сменном носителе или в сети.
И правильно делает. Считать с ЖД в память 50 Мб -- дело долей секунды.
-
> для этого надо городить отдельный поток. а если у меня будет > 500 файлов читаться?
Одновременно ? Разница при любом подходе будет малозначительной, винда повиснет наглухо :-)
-
> И правильно делает. > Считать с ЖД в память 50 Мб -- дело долей секунды.
тоже верно... видимо основную задержку при вызове ReadFile создает копирование памяти...
-
А зачем вообще читать десятки мегабайт в память? Нужно просто мапить этот файл на память и всё. Никаких проблем. Работу с файлом оформить в отдельный поток.
-
> Нужно просто мапить этот файл на память и всё. Никаких проблем. > > Работу с файлом оформить в отдельный поток.
+1
-
собстно это было мое исследование(попытки) работы с overlapped. всем спасибо за участие!
-
учитывая рост количества ядер в процах, имеет смысл ориентироваться на синхронную архитектуру, а не наоборот.
-
а почему?
-
потому что при увеличении числа ядер/процессоров уменьшаются накладные расходы на переключение контекстов потоков, не говоря уже об общем повышении производительности.
-
а разве утверждение, что "оптимальное кол-во потоков равно числу ядер/процессоров" неверно?
-
Неверно в корне. Во-первых, есть ещё такая штука как гипертрединг (который обещают вернуть в следующих поколениях многоядерников). Во-вторых, есть и другие (и системные в том числе) процессы со своими потоками. В-третьих, ваши потоки когда-нибудь будут ждать. ... А есть ещё и в-пятых, и в-двадцатых...
-
> Eraser © (26.12.07 21:18) [14] > учитывая рост количества ядер в процах, имеет смысл ориентироваться > на синхронную архитектуру, а не наоборот.
Не вижу логики. Что ты называешь синхронной архитектурой? Наоборот, сейчас имеет смысл распараллеливать всё что можно, то есть всё делать асинхронно. И чем дальше, тем это становится более актуально. Например, в ближайшие пару лет появятся 8-ми ядерные процессоры, а на них может быть гипертрединг, тогда чем сильнее распараллелишь, тем быстрее будет работать (там где это имеет смысл, естественно). Кстати, Delphi в этом плохой помошник, точнее вообще никакой, и никаких намёков на улучшение ситуации.
-
> Alex Konshin © (27.12.07 10:48) [19]
> Что ты называешь синхронной архитектурой?
В данном случае я имею ввиду архитекуру, при которой для каждого соединения создается отдельный поток. асинхронная арихеткура как раз подразумевает то, что достаточно всего одного потока для работы со множеством соединений, в ряде случаев это дейтсивительно дает приемущество, но учитывая [14] подход будет меняться, тем более что с т.з. программиста организоваться синхронную передачу данных куда проще. Насчет распараллеливания полностью согласен, через несколько лет появятся встроенные языковые средства для поддержки многопоточности.
-
> через несколько лет появятся встроенные языковые средства > для поддержки многопоточности
какие такие средства? а TThread - это не средство?
-
> MetalFan © (27.12.07 17:21) [21]
нет, TThread это не языковое средство поддержки многопоточности.. единственное языковое средство в Делфи, связанное с многопоточностью приходит на ум только ThreadVar.
-
> Eraser © (27.12.07 17:37) [22]
понял. спасибо)
-
Удалено модератором
|