Форум » [x]Harbour » Как сделать многопотоковую проверку Базы ? » Ответить

Как сделать многопотоковую проверку Базы ?

Andrey: Есть ряд задач (переодически возникающих) на которые тратиться много времени. Может быть я и не прав. Вот например: база 20 тыс.записей, каждую запись нужно пройти и проверить заполнение полей, если не заполнено - ошибку в тхт-файл. Все (наверно) делают последовательную обработку, т.е. проверяем базу с 1 по N-запись.. А можно же через потоки сделать ? Подскажите как примерно это можно сделать для хХарбора ? Заранее спасибо..

Ответов - 78, стр: 1 2 3 4 All

alkresin: А в чем, собственно, проблема ? Запускаем поток, открываем в нем базу и проверяем, примерно так: ... hb_threadDetach( hb_threadStart( @TestBase() ) ) ... Function TestBase() use mybase shared new do while !Eof() if ... ... endif skip enddo Return Nil

Andrey: alkresin пишет: А в чем, собственно, проблема ? То что вы мне предлагаете, это ОПЯТЬ ПОСЛЕДОВАТЕЛЬНАЯ проверка базы, только в фоновом потоке. Правильно ? А я хочу МНОГОПОТОЧНУЮ проверку базы... Может я неправильно выражаюсь, тогда извините меня. Я хочу чтобы ну допустим 30-40 потоков проверили базу, причем каждый поток проверял свои записи, а уже проверенные не трогал... Т.е. количество записей делим на количество потоков и каждый поток проверяет СВОИ записи. Вот примерно так хочу ускорить проверку.... Как такое можно реализовать ? Будет ли выигрыш по времени ?

a_sidorov: Обработку записей базы я делаю через dbeval(), работает в десятки раз быстрее. А перебирать по записи, по моему, нерационально.


alkresin: Andrey пишет: Я хочу чтобы ну допустим 30-40 потоков проверили базу, причем каждый поток проверял свои записи, а уже проверенные не трогал... Ну тогда вот так: ... hb_threadDetach( hb_threadStart( @TestBase() ),1,5000 ) hb_threadDetach( hb_threadStart( @TestBase() ),5001,10000 ) hb_threadDetach( hb_threadStart( @TestBase() ),10001,15000 ) hb_threadDetach( hb_threadStart( @TestBase() ),15001,20000 ) ... Function TestBase( nRec1, nRec2 ) use mybase shared new go to nrec1 do while !Eof() .and. Recno()<=nRec2 if ... ... endif skip enddo Return Nil Если будете результаты писать в один текстовый файл, то операцию записи надо mutex'ом синхронизировать ( hb_mutexLock() ... hb_mutexUnLock() ) Будет ли выигрыш по времени ? Может быть :). a_sidorov пишет: Обработку записей базы я делаю через dbeval(), работает в десятки раз быстрее Ну это вы загнули... На локальной БД небольшой выигрыш во времени может иметь место, а в сети разница будет неощутима - временные затраты на операции перемещения по базе и чтения данных существенно выше, чем обработка нескольких строк кода.

Andrey: alkresin пишет: Если будете результаты писать в один текстовый файл, то операцию записи надо mutex'ом синхронизировать ( hb_mutexLock() ... hb_mutexUnLock() ) А можно чуть подробнее.... Допустим: Function Main() ..... cErrorFile := "myerror.log" ..... hb_threadDetach( hb_threadStart( @TestBase() ),1,5000, cErrorFile) hb_threadDetach( hb_threadStart( @TestBase() ),5001,10000, cErrorFile ) hb_threadDetach( hb_threadStart( @TestBase() ),10001,15000, cErrorFile ) hb_threadDetach( hb_threadStart( @TestBase() ),15001,20000, cErrorFile ) ... Function TestBase( nRec1, nRec2, cErrorFile ) LOCAL cError:="" use mybase shared new go to nrec1 do while !Eof() .and. Recno()<=nRec2 if ... ... // если ошибка, то добавляем в строку сError += "Error ...."+CRLF endif skip enddo // --- здесь будет запись в cErrorFile... строки cError ! // Как сделать ? Return Nil

alkresin: Где-то в начале программы: static mutex1 Затем, перед запуском потоков: mutex1 := hb_mutexCreate() Ну и в TestBase(): hb_mutexLock( mutex1 ) // --- здесь будет запись в cErrorFile... строки cError ! hb_mutexUnLock( mutex1 )

Andrey: СПАСИБО БОЛЬШОЕ ! Буду пробовать...

Dima: Andrey пишет: Буду пробовать... Поведай нам потом есть ли выигрыш по скорости. Что то мне кажется если он и будет то будет не существенный.

Andrey: Dima пишет: Поведай нам потом есть ли выигрыш по скорости. Обязательно !

Andrey: alkresin пишет на http://kresin.belgorod.su/rus/hrbfaq.html#Doc11: Другие примеры многопоточных программ вы можете найти в harbour/tests/mt. А для хХарбора где можно найти функции и примеры ? Я пока на хХарборе сижу....

AlexMyr: Andrey пишет: А для хХарбора где можно найти функции и примеры ? в папке tests/mt*.prg

Andrey: Сделал пока однопотоковый тест проверки базы и понял где "тормоза" можно убрать. При проверке базы, если ошибка, то я использую CT-функцию: STRFILE( "Ошибка ... такая то...", cFileError, .T.) Да еще и в цикле проверки. Если её убрать, то проверка просто "влет" ускоряется.... Может ошибки писать в массив, а потом сбрасывать на диск ? Нужно ли заменить STRFILE() и чем ? Народ, подскажите как вы создаете текстовые журналы-ошибок для пользователя ?

PSP: Вот как раз отдельный поток мог бы делать журналирование, имхо.

Andrey: Народ, помогите протестировать мою тестовую программу. А потом пришлите log-файл теста: dBase2test.log У меня комп слишком шустрый для таких тестов... --------------------------------------------------------------------------- CPU: Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz [~3504 MHz] Free RAM: 2 097 151 OS: Windows Windows Vista Professional 6.02.9200 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 01 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 01 seconds Second test base - 00 hour 00 minute 02 seconds Third test base - 00 hour 00 minute 02 seconds Fourth test base - 00 hour 00 minute 03 seconds The total test time ---> 00 hour 00 minute 11 seconds Это тест на 30000 записей, можно поставить и 70000 (есть такие клиенты). Конечно же реально кол-во ошибок в журналах меньше чем сейчас создается в тесте... Исходник и сама программа здесь - http://files.mail.ru/5A8E598290604D31955459BEFBDF3FD3 Какие будут рекомендации для ускорения работы этой программы для ОДНОПОТОКОВОЙ работы для локальной программы ? Для сетевой задачи журнал-ошибок нужно наверно все таки писать на локальную станцию...

nick_mi: Для сетевой работы журнал лучше писать в dbf файл ИМХО конечно. А если в DBF завести последнее поле длиной 2 символа и туда писать chr(13)+ chr(10) и отформатировать выводимую запись, то такую БД можно будет просматривать любым редактором. За исключением абракадабры в заголовке DBFинфорация будет вполне читаема и без специальных программ типа DBU

Andrey: nick_mi пишет: За исключением абракадабры в заголовке DBFинфорация будет вполне читаема и без специальных программ типа DBU Это пользователь будет читать ? Как ты ему это объяснишь ?

nick_mi: Ну если вопрос стоит о том, чтобы смотрел пользователь, значит для него простенькую программу просмотра, а если уж очень влом писать программу просмотра или журнал вообще предназначен в первую очередь тебе для разборок полетов, в первую запись базы вносишь данные CHR(13) + CHR(10) + "***ЖУРНАЛ РАБОТЫ***" + CHR(13) + CHR(10) . А пользователю объясняешь: Все что до того - служебная информация, а ниже того - для пользовательского внимания

SergKis: Andrey пишет:Какие будут рекомендации Может вот так [pre2] #include "i_winuser.ch" #include "minigui.ch" #include "hbclass.ch" #include "hbwin.ch" MEMVAR oPub FUNCTION MAIN() LOCAL i,j,k, aYes,oL,oE PUBLIC oPub := MyPubl():New() MyFunc() oPub:Destroy() RETURN FUNCTION MyFunc() LOCAL i,j,k, aYes,oL,oE aYes := { "Text ", 10.00, 20.00, Date() } k := 10 oE := oPub:oErr oL := oPub:oLog oE:Put(repl("=",10), Date(), repl("=", 20)) oL:Put(repl("=",10), Date(), repl("=", 20)) FOR i := 1 TO k oPub:oLog:Put( PadR(aYes[1]+ltrim(str(i)), 20), ; PadL(aYes[2] * i, 12), ; PadL(aYes[3] * i, 12), ; PadC(aYes[4] + i, 12) ) IF i == 3 .or. i == 7 oE:Put("Error <", ltrim(str(i)), ">") ENDIF NEXT RETURN CLASS ToFile // Класс вывода в файл txt VAR cFile INIT '' VAR hFile INIT 0 VAR cTab INIT '' VAR cCrLf INIT '' METHOD New() METHOD Open() METHOD Close() METHOD Put() METHOD PutTab() METHOD PutCrLf() METHOD Val2Txt() ENDCLASS METHOD New( cFile ) CLASS ToFile IF ! empty(cFile) .and. valtype(cFile) == "C" ::cFile := cFile ENDIF ::cTab := chr(9) ::cCrLf := chr(13)+chr(10) RETURN Self METHOD Open() IF empty(::cFile); RETURN .F. ENDIF ::hFile := iif( File(::cFile), FOpen(::cFile, 2) , FCreate(::cFile) ) IF ::hFile > 0; FSeek( ::hFile, 0, 2 ) ENDIF RETURN ( ::hFile > 0 ) METHOD Close() CLASS ToFile IF ::hFile > 0 FClose( ::hFile ) ::hFile := 0 ENDIF RETURN METHOD Put( ... ) CLASS ToFile LOCAL i,j, aParams, nParams, lParams nParams := PCount() IF ::hFile < 1 .or. nParams < 1; RETURN ENDIF aParams := hb_aParams() lParams := nParams > 1 FOR i := 1 TO nParams j := ::Val2Txt( aParams [ i ] ) IF len(j) > 0; FWrite(::hFile, j) ENDIF IF i != nParams .and. lParams; ::PutTab() ENDIF NEXT IF lParams; ::PutCrlf() ENDIF RETURN METHOD PutTab() CLASS ToFile IF len(::cTab) > 0; FWrite(::hFile, ::cTab) ENDIF RETURN METHOD PutCrLf() CLASS ToFile IF len(::cCrLf) > 0; FWrite(::hFile, ::cCrLf) ENDIF RETURN METHOD Val2Txt( xVal ) CLASS ToFile LOCAL cTx := "", cTp := valtype(xVal) IF cTp=='C'; cTx := xVal ELSEIF cTp=='N'; cTx := LTrim(Str(xVal)) ELSEIF cTp=='L'; cTx := iif(xVal, "Yes", "No ") ELSEIF cTp=='D'; cTx := DToC( xVal ) ELSEIF cTp=='A'; AEval(xVal, {|x,i| cTx += x + ::cTab }) ENDIF RETURN cTx CLASS MyPubl // Класс контейнер VAR oLog VAR oErr METHOD New() METHOD Destroy() ENDCLASS METHOD New() CLASS MyPubl ::oLog := ToFile():New("_MyLog.txt") ::oErr := ToFile():New("_MyErr.txt") ::oLog:Open() ::oErr:Open() RETURN Self METHOD Destroy() CLASS MyPubl ::oLog:Close() ::oErr:Close() RETURN [/pre2]

Andrey: Да вопрос то по другому стоит: Какие будут рекомендации для ускорения работы этой программы для ОДНОПОТОКОВОЙ работы для локальной программы ? В чем разница по скорости записи: 1) CT-функции STRFILE() 2) Или то что предлагает nick_mi nick_mi пишет: Для сетевой работы журнал лучше писать в dbf файл ИМХО конечно. Запись в DBF это 2 операции: APPEND BLANK и запись в поле STRFILE() наверно 4... (Я не знаток) открыть файл, указатель файла в конец файла, запись в файл, закрыть файл. Самые МЕДЛЕННЫЕ операции - это: открытие и закрытие файлов... Но тогда я сам могу создать функцию записи в журнал. Один раз его открыть в начале, потом писать в него (2 операции, указатель в конец файла и запись строки) и в конце проверки - закрыть файл. Будет наверно быстрее.... Народ, помогите протестировать мою тестовую программу. Ссылка вверху !

nick_mi: An example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Intel(R) Pentium(R) CPU G645 @ 2.90GHz [~2894 MHz] Free RAM: 1 298 096 OS: Windows XP Professional 5.01.2600 Service Pack 3 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 03 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 02 seconds Second test base - 00 hour 00 minute 05 seconds Third test base - 00 hour 00 minute 02 seconds Fourth test base - 00 hour 00 minute 08 seconds The total test time ---> 00 hour 00 minute 21 seconds

SergKis: An example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Genuine Intel(R) CPU T2130@ 1.86GHz [~1867 MHz] Free RAM: 1 387 068 OS: Windows Windows Vista Home Edition 6.01.7601 Service Pack 1 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 19 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 16 seconds Second test base - 00 hour 02 minute 30 seconds Third test base - 00 hour 00 minute 10 seconds Fourth test base - 00 hour 03 minute 55 seconds The total test time ---> 00 hour 07 minute 12 seconds Andrey пишет:Но тогда я сам могу создать функцию записи в журнал. Один раз его открыть в начале, потом писать в него (2 операции, указатель в конец файла и запись строки) и в конце проверки - закрыть файл. В моем примере (на классах так и сделано). Тексты выдернул из реальной проги MiniGUI, адаптировать к xHb - не должно составить труда. Вывод поколоночно с разделителем chr(9) в файлы log и err. Если что то не понятно - спрашивай. Сам работаю так: log файлы локально (имена рабочее место или имя (код) usera). Просмотр редактором. Если надо объединять, то через copy на сервер или иначе. Если просмотр через Browse - тогда конечно dbf.

Dima: У меня вот такой результат. Просто жесть (Исходник не смотрел) An example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz [~3011 MHz] Free RAM: 932 676 OS: Windows XP Professional 5.01.2600 Service Pack 2 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 09 seconds ( Recno: 30000 ) First test base - 00 hour 09 minute 37 seconds Second test base - Оборвал через 1 час на 30 %

Dima: Тот же тест на Clipper (First test base) 5 секунд -//- Harbour -//- порядка 9 минут Тормоз в STRFILE (Harbour) Намного быстрее если результат писать в базу. Можно сразу или писать в начале в массив а потом в базу [Проверил] А можно еще проще используя Alternate файлик вместо STRFILE , работает быстро.

santy: An example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Pentium(R) Dual-CoreCPUE5700@ 3.00GHz [~3000 MHz] Free RAM: 2 097 151 OS: Windows XP Professional 5.01.2600 Service Pack 3 Development: xHarbour 1.2.3 Intl. (SimpLex) (Build 20121213) - Open Watcom C 12.90 (32 bit) Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 05 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 01 seconds Second test base - 00 hour 00 minute 04 seconds Third test base - 00 hour 00 minute 01 seconds Fourth test base - 00 hour 00 minute 05 seconds The total test time ---> 00 hour 00 minute 17 seconds *********************************** An example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Pentium(R) Dual-CoreCPUE5700@ 3.00GHz [~3000 MHz] Free RAM: 2 097 151 OS: Windows XP 5.1.2600 Service Pack 3 Development: Harbour 3.2.0dev (Rev. 18748) - Open Watcom C 12.90 (32-bit) Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 05 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 01 seconds Second test base - 00 hour 00 minute 04 seconds Third test base - 00 hour 00 minute 00 seconds Fourth test base - 00 hour 00 minute 05 seconds The total test time ---> 00 hour 00 minute 17 seconds ******************************** An example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Pentium(R) Dual-CoreCPUE5700@ 3.00GHz [~3000 MHz] Free RAM: 2 009 484 OS: Windows XP Professional 5.01.2600 Service Pack 3 Development: xHarbour 1.2.3 Intl. (SimpLex) (Build 20121213) - Borland C++ 5.8.2 (32 bit) Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 05 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 01 seconds Second test base - 00 hour 00 minute 05 seconds Third test base - 00 hour 00 minute 01 seconds Fourth test base - 00 hour 00 minute 07 seconds The total test time ---> 00 hour 00 minute 20 seconds ************************* An example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Pentium(R) Dual-CoreCPUE5700@ 3.00GHz [~3000 MHz] Free RAM: 2 029 332 OS: Windows XP 5.1.2600 Service Pack 3 Development: Harbour 3.2.0dev (Rev. 18748) - Borland C++ 5.8.2 (32-bit) Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 04 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 01 seconds Second test base - 00 hour 00 minute 05 seconds Third test base - 00 hour 00 minute 00 seconds Fourth test base - 00 hour 00 minute 07 seconds The total test time ---> 00 hour 00 minute 19 seconds

Dima: Dima пишет: First test base - 00 hour 09 minute 37 seconds santy пишет: First test base - 00 hour 00 minute 01 seconds Фига себе разница.........

SergKis: Андрей, глянул prg: FUNCTION Third_Test_DBF(cFileError,cPOLE) добавьте:[pre2] LOCAL nPOLE, ; // позиция поля cPOLE в файле nNNN, ; // позиция поля ABONENT->NNN в файле nNN, ; // позиция поля ABONENT->NN в файле nKCity, ; // позиция поля ABONENT->KCity в файле nKStreet // позиция поля ABONENT->KStreet в файле ... SELECT ABONENT DbSetOrder(1) nKolRecords := ORDKEYCOUNT() nPOLE := FieldPos(cPOLE) nNNN := FieldPos("NNN") nNN := FieldPos("NN") nKCity := FieldPos("KCity") nKStreet := FieldPos("KStreet") ... cNNN := FieldGet(nPOLE) // cNNN := ABONENT->&cPOLE aYes := {} DO WHILE cNNN == FieldGet(nPOLE) // ABONENT->&cPOLE ... // заменить ABONENT->NNN на FieldGet(nNNN) // заменить ABONENT->NN на FieldGet(nNN) // и так далее AADD( aYes, cStr ) // этот массив лишний, надо сразу вывод в cFileError SKIP ENDDO IF LEN(aYes) > 1 ... AADD(aDimNNN, cStr ) // этот массив лишний, надо сразу вывод в cFileError ENDIF ... [/pre2] дальше по тексту, наверное, также поступить.

Andrey: Dima пишет: Тот же тест на Clipper (First test base) 5 секунд -//- Harbour -//- порядка 9 минут Тормоз в STRFILE (Harbour) Вот вот и я о том же... Клипер на многих вещах работает быстрее Харбора... Взять бы тот же SET FILTER TO - там оптимизация есть, а в Харборе нет... Переделал прогу на Харбор и успокоился... Ан нет нужно перепроверять !!! Я понял, что нужно писать свой STRFILE() ! Dima пишет: CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz [~3011 MHz] Free RAM: 932 676 Самая классная машина для тестирования ! А то наставили всякого нового железа (включая меня самого) и все, алгоритмы побоку... Типа и так сойдет... А юзера страдают...

Andrey: SergKis пишет: DO WHILE cNNN == FieldGet(nPOLE) // ABONENT->&cPOLE ... // заменить ABONENT->NNN на FieldGet(nNNN) // заменить ABONENT->NN на FieldGet(nNN) Понял, спасибо ! Это для ускорения. SergKis пишет: AADD( aYes, cStr ) // этот массив лишний, надо сразу вывод в cFileError SKIP Тогда получиться лишний вывод равный количеству повтора... А операция создания массива aYes := {} и заполнения его - разве медленная ? SergKis пишет: IF LEN(aYes) > 1 ... AADD(aDimNNN, cStr ) // этот массив лишний, надо сразу вывод в cFileError ENDIF Я специально сделал вывод ОДНОГО значения повтора + перескок по базе на нужную запись минуя одинаковые: nI := nI + LEN(aYes) - 1

Dima: Andrey пишет: Я понял, что нужно писать свой STRFILE() Ты выше то читал ? Для этой задачи вполне покатит Set cons off Set alter on Set Alter to твой файлик ,,,,,,,,,,,,,,,, твой код ? "что то пишем в твой файл" close alter set alter off Ни когда не юзал что ли ?

Andrey: santy пишет: Development: xHarbour 1.2.3 Intl. (SimpLex) (Build 20121213) - Open Watcom C 12.90 (32 bit) The total test time ---> 00 hour 00 minute 17 seconds Development: Harbour 3.2.0dev (Rev. 18748) - Open Watcom C 12.90 (32-bit) The total test time ---> 00 hour 00 minute 17 seconds Development: xHarbour 1.2.3 Intl. (SimpLex) (Build 20121213) - Borland C++ 5.8.2 (32 bit) The total test time ---> 00 hour 00 minute 20 seconds Development: Harbour 3.2.0dev (Rev. 18748) - Borland C++ 5.8.2 (32-bit) The total test time ---> 00 hour 00 minute 19 seconds Разница между: Harbour 3.2.0dev и xHarbour 1.2.3 вообще ни какая... А мой тест ( xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 ) сколько показывает ? santy пишет: Development: Harbour 3.2.0dev (Rev. 18748) - Open Watcom C 12.90 (32-bit) А тест на 70000 записей попробуй сделать ?

Andrey: Dima пишет: Ни когда не юзал что ли ? Неа ... не юзал ... А эти операторы быстрее будут: hFile:=Fopen(cFileError,FO_WRITE) ..... do while ... ...... FSEEK(hFile,0,FS_END) Fwrite(hFile, cStream, LEN(cStream)) ..... enddo ...... FClose( hFile )

Dima: Andrey пишет: Неа ... не юзал ... Юзани ;) Andrey пишет: А эти операторы быстрее будут: hFile:=Fopen(cFileError,FO_WRITE) ..... do while ... ...... FSEEK(hFile,0,FS_END) Fwrite(hFile, cStream, LEN(cStream)) ..... enddo ...... FClose( hFile ) Вот так будет быстрее на много порядков Set alter on Set alter to test.txt ..... do while ... ...... ? cStream ..... enddo ...... close alter set alter off

Andrey: Dima пишет: Вот так будет быстрее на много порядков Set alter on Set alter to test.txt Блин, а бегунок (проценты показа) тоже же будут в файл писаться (ударение на "а" ) ! Как там переключать то на экран/файл ? Я уже забыл....

Dima: Andrey пишет: Блин, а бегунок (проценты показа) тоже же будут в файл писаться (ударение на "а" ) ! НЕА ;)

Andrey: Вот блин поправил.... И МНОГОПОТОЧНУЮ проверку в этом случае делать не надо .... The second example of measuring the speed of processing database for [x]Harbour --------------------------------------------------------------------------- CPU: Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz [~3504 MHz] Free RAM: 2 097 151 OS: Windows Windows Vista Professional 6.02.9200 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 02 seconds ( Recno: 70000 ) First test base - 00 hour 00 minute 04 seconds Second test base - 00 hour 00 minute 01 seconds Third test base - 00 hour 00 minute 04 seconds Fourth test base - 00 hour 00 minute 01 seconds The total test time ---> 00 hour 00 minute 14 seconds Предыдущая программа dBase2test.exe на этом же компе и с этой же базой: The total test time ---> 00 hour 00 minute 32 seconds Исходник и ехе-ник здесь - http://files.mail.ru/8842CDB5260248C8BB975F82D70C666E Народ, проверьте у себя пожалуйста !

Dima: Andrey The second example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz [~3011 MHz] Free RAM: 837 448 OS: Windows XP Professional 5.01.2600 Service Pack 2 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 00 seconds ( Recno: 30000 ) First test base - 00 hour 00 minute 06 seconds Second test base - 00 hour 00 minute 03 seconds Third test base - 00 hour 00 minute 06 seconds Fourth test base - 00 hour 00 minute 04 seconds The total test time ---> 00 hour 00 minute 20 seconds

Dima: Andrey пишет: И МНОГОПОТОЧНУЮ проверку в этом случае делать не надо Ихгде ты ее делал ? Ни в одном твоем примере ее нет.

Andrey: Dima пишет: Ихгде ты ее делал ? Ни в одном твоем примере ее нет. Так я только собирался... Следующую проверку (тест) буду делать !

SergKis: The second example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Genuine Intel(R) CPU T2130@ 1.86GHz [~1867 MHz] Free RAM: 1 362 460 OS: Windows Windows Vista Home Edition 6.01.7601 Service Pack 1 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 41 seconds ( Recno: 70000 ) First test base - 00 hour 00 minute 19 seconds Second test base - 00 hour 00 minute 04 seconds Third test base - 00 hour 00 minute 21 seconds Fourth test base - 00 hour 00 minute 06 seconds The total test time ---> 00 hour 01 minute 34 seconds Andrey пишет:А операция создания массива aYes := {} и заполнения его - разве медленная ? Если бы массив создавался один раз, а в данном случае происходит запрос,выделение памяти, освобождение и в какой то момент будет работать сборщик мусора, приостанавливающий работу программы - это конечно мелочь в сравнении с STRFILE, но иногда помнить об этом надо.

santy: The second example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Pentium(R) Dual-CoreCPUE5700@ 3.00GHz [~3000 MHz] Free RAM: 2 097 151 OS: Windows XP Professional 5.01.2600 Service Pack 3 Development: xHarbour 1.2.3 Intl. (SimpLex) (Build 20121213) - Open Watcom C 12.90 (32 bit) Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 10 seconds ( Recno: 70000 ) First test base - 00 hour 00 minute 02 seconds Second test base - 00 hour 00 minute 01 seconds Third test base - 00 hour 00 minute 01 seconds Fourth test base - 00 hour 00 minute 01 seconds The total test time ---> 00 hour 00 minute 18 seconds

Andrey: Dima пишет: CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz [~3011 MHz] Free RAM: 837 448 OS: Windows XP Professional 5.01.2600 Service Pack 2 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- The total test time ---> 00 hour 00 minute 20 seconds Даже на слабенькой машине теперь все летает ! Значит STRFILE() в Харборе - отстой....

alkresin: Все в порядке с Strfile(), просто надо знать, в каких случаях ее использование целесообразно, а в каких - нет. Она сначала проверяет, если файл с именем, которые вы ей передали, потом, в зависимости от результата, создает новый или открывает существующий, записывает туда строку и закрывает его. Делать это в цикле, естественно, крайне нерационально.

Andrey: alkresin пишет: Делать это в цикле, естественно, крайне нерационально. Сейчас согласен с этим. А на Клипере все работало без "тормозов"... Дима проверял.

Andrey: Вот нашел старичка - ноутбук Samsung R40. Неплохую скорость показывает.... The second example of measuring the speed of processing database for [x]Harbour --------------------------------------------------------------------------- CPU: Intel(R) Celeron(R) M CPU410@ 1.46GHz [~1468 MHz] Free RAM: 1 354 160 OS: Windows XP Home Edition 5.01.2600 Service Pack 3 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 14 seconds ( Recno: 70000 ) First test base - 00 hour 00 minute 11 seconds Second test base - 00 hour 00 minute 03 seconds Third test base - 00 hour 00 minute 09 seconds Fourth test base - 00 hour 00 minute 04 seconds The total test time ---> 00 hour 00 minute 43 seconds

MTC: У меня Win8 Pro, а прога выдает какую-то Vista ... Абидна, да! The second example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Intel(R) Core(TM) i7-3610QM CPU @ 2.30GHz [~2296 MHz] Free RAM: 2 752 236 OS: Windows Windows Vista Professional 6.02.9200 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 00 seconds ( Recno: 70000 ) First test base - 00 hour 00 minute 04 seconds Second test base - 00 hour 00 minute 01 seconds Third test base - 00 hour 00 minute 04 seconds Fourth test base - 00 hour 00 minute 01 seconds The total test time ---> 00 hour 00 minute 11 seconds

Andrey: MTC пишет: У меня Win8 Pro, а прога выдает какую-то Vista ... Абидна, да! Да у меня тоже самое выдает .... CPU: Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz [~3504 MHz] OS: Windows Windows Vista Professional 6.02.9200 В хХарборе 1.2 и 1.0 нет функции определения для Win8 ... А как самому написать/переделать в winos.prg я не знаю...

PSP: Андрей, думаю, что исправление winos.prg тут не требуется. Может вместо функции OS() использовать, к примеру, OS_VersionInfo()? Это, собственно, winos.prg: http://sourceforge.net/p/xharbour/code/9908/tree/trunk/xharbour/source/rtl/winos.prg Там есть и 7-ка, и 8-ка... У Висты версия 6.0, у 7-ки - 6.1, у 8-ки - 6.2 update: мдаааа, чё-та OS_VersionInfo() тоже не хочет... Проще свою написать.

Andrey: PSP Спасибо БОЛЬШОЕ !

PSP: Не спеши... ))) Я там подправил сообщение. Проверь функцию. update: Проверил в Харборе WIN_OSVersionInfo(). Нормально работает. WIN_OSVersionInfo()[ 2 ] на 7-ке выдало "1".

Andrey: Вот сделал другой тест (запись части полей из одной БД в другую), хоть немного нагружает машину. --------------------------------------------------------------------------- CPU: Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz [~3504 MHz] Free RAM: 2 097 151 OS: Windows Windows Vista Professional 6.02.9200 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 04 seconds ( Recno: 2525/127500 ) Write test base - 00 hour 04 minute 06 seconds The total test time ---> 00 hour 04 minute 11 seconds Может его можно переделать в МНОГОПОТОЧНЫЙ ? Исходник и прога здесь - http://files.mail.ru/FCA060C7F8654447B070A668070E4981 Пробую прогнать свой тест на реальных данных, почему то выходит порядка 30 минут ? Почему ??? Может из-за того что в ОБЩЕЙ системе (кроме одного этого теста) есть много других функций ? Размер моей ОБЩЕЙ проги на хХарборе 5152 Кб (в памяти занимает 70,3 Мб, загрузка проца 3% ), а тестового примера dBase5test.exe - 842752 байт (в памяти занимает 1,4 Мб, загрузка проца 30% ) ...... Странное несоответствие теста и реальной программы....

SergKis: Andrey пишет:Может его можно переделать в МНОГОПОТОЧНЫЙ ? Надо сначала его почистить - лишние перегонки данных по памяти убрать, а потом смотреть: [pre2] FUNCTION Write_Test_DBF(cFileError,cPOLE) ... cStr := CLRF + CLRF + PADC("",75,"-") + CLRF cStr += PADC("Record fields from the first database to the second database",75) + CLRF cStr += PADC("",75,"-") + CLRF + CLRF FWrite( nHandle, cStr, Len(cStr) ) Замените на: FWrite( nHandle, CRLF ) FWrite( nHandle, CRLF ) FWrite( nHandle, PADC("",75,"-") ) FWrite( nHandle, CRLF ) FWrite( nHandle, PADC("Record fields from the first database to the second database",75)) FWrite( nHandle, CRLF ) FWrite( nHandle, PADC("",75,"-") ) FWrite( nHandle, CRLF ) FWrite( nHandle, CRLF ) ... nKCity := FieldPos("KCity") // вынести сюда или в начале prg файла перечислите все поля dbf nKStreet := FieldPos("KStreet") // FIELD KCity,KSteet,FIO,NNN,NN... и используйте их без Alias-> и FIELD-> // для тек. alias FOR nI := 1 TO nKolRecords ... cStr := " ID abonent: "+STR(FIELD->NNN) + " , Dogovor:"+STR(FIELD->NN) + CLRF cStr += "FIO abonent: "+FIELD->FIO + CLRF cStr += " Adres: "+STR(FieldGet(FieldPos("KCity"))) + STR(FieldGet(FieldPos("KStreet")))+ CLRF Замените на: FWrite( nHandle, " ID abonent: " ) FWrite( nHandle, STR(FIELD->NNN) ) // или FWrite( nHandle, NNN ) FWrite( nHandle, " , Dogovor:" ) FWrite( nHandle, STR(FIELD->NN) ) // или FWrite( nHandle, NN ) FWrite( nHandle, CRLF ) FWrite( nHandle, "FIO abonent: " ) FWrite( nHandle, FIELD->FIO ) // или FWrite( nHandle, FIO ) FWrite( nHandle, CRLF ) FWrite( nHandle, " Adres: " ) FWrite( nHandle, STR(FieldGet(nKCity)) ) // или FWrite( nHandle, KCity ) FWrite( nHandle, STR(FieldGet(nKStreet)) ) // или FWrite( nHandle, KStreet ) FWrite( nHandle, CRLF ) и так далее по тексту. ... IF FIELD->NNN == 0 cStr += " ! Error: NNN = 0. Change it."+CLRF+CLRF FSeek( nHandle, 0, FS_END ) // это зачем ? таких мест несколько FWrite( nHandle, cStr, Len(cStr) ) cDogovor := "Is not in DB" nJ++ ENDIF ... зачем использовать промежуточные переменные, можно сразу: SELECT ABONENT IF ( RecLock( LOCK_RETRY ) ) ABONENT->NDog := cDogovor IF UPPER(cDogovor) == "IS NOT IN DB" ABONENT->LASTNAME := cDogovor ABONENT->YES := -2 // The data in the records is not corrected //DBDELETE() ELSEIF UPPER(cDogovor) == "IS NOT NN" ABONENT->LASTNAME := cDogovor ABONENT->YES := -1 // The data in the records is not corrected //DBDELETE() ELSE nYes++ ABONENT->YES := 1 // Data in the record corrected ABONENT->KCity := DOGOVOR->KCity // nCity ABONENT->KOkrug := DOGOVOR->KOkrug // nOkrug ... ABONENT->KZakaz := DOGOVOR->KZakaz // nZakaz ENDIF DBCOMMIT() DBUNLOCK() [/pre2]

SergKis: SergKis пишет:Надо сначала его почистить Вдогонку. Возможно надо воспользоваться функциями, которые выкладывал Паша на сайте и использует их в DbEdit.prg (тексты в конце prg). Я говорю о dbGetValue(...) и dbPutValue(...). [pre2]// Получить значение поля как строка: // --------------------------- // if FieldType(nPos) == "C"; xVal := FieldGet(nPos) // else ; xVal := dbGetValue(nPos) // endif // ----------------------------- // Сохранить значение поля как строка: // --------------------------- // if FieldType(nPos) == "C"; FieldPut(nPos, xVal) // else ; dbPutValue(nPos, xVal) // endif // ----------------------------- исключаются преобразования типов. [/pre2]

SergKis: Andrey насколько актуально DBCOMMIT() после кажной записи, а не через 10 или 100 ?

Andrey: SergKis пишет: nKCity := FieldPos("KCity") // вынести сюда или в начале prg файла перечислите все поля dbf nKStreet := FieldPos("KStreet") // FIELD KCity,KSteet,FIO,NNN,NN... и используйте их без Alias-> и FIELD->// для тек. alias Насколько это актуально ? Можно ли обойтись без этого ? А то код непривычно читать .... Если нельзя, то будем привыкать... SergKis пишет: FSeek( nHandle, 0, FS_END ) // это зачем ? таких мест несколько А при такой записи в файл, указатель ВСЕГДА остается в конце файла ? Я просто не знаю. SergKis пишет: насколько актуально DBCOMMIT() после кажной записи, а не через 10 или 100 ? Вообще не актуально... Ваши рекомендации ? Насчет остального понял. Спасибо БОЛЬШОЕ !

SergKis: Andrey пишет:А то код непривычно читать .... [pre2] aAbn := array(20) aAbn[1] := {"KCity" , 0, 0, NIL} aAbn[2] := {"KStreet", 0, 0, NIL} ... sele DOGOVOR AEval(aAbn, {|a,n| a[ 3 ] := FieldPos(a[ 1 ])}) sele ABONENT AEval(aAbn, {|a,n| a[ 2 ] := FieldPos(a[ 1 ])}) ... FOR i := 1 TO nKolRecords ... sele ABONENT AEval(aAbn, {|a,n| a[ 4 ] := FieldGet(a[ 2 ])}) ... sele DOGOVOR AEval(aAbn, {|a,n| FieldPut(a[ 3 ], a[ 4 ])}) ... на мой взгляд, кратко и понятно. [/pre2] Если другого exe-шника нет подключенного к базе - DBCOMMIT() перед закрытием табл., иначе надо смотреть как быстро измененные данные должны попадать на диск.

Andrey: Andrey пишет: Странное несоответствие теста и реальной программы Разобрался я в этой ситуации... Я тестировал прогу на одном компе но на разных винчестерах: SSD и обычном. Если база располагается на SSD - то загрузка проца возрастает и тест-dBase5test.exe проходит в 14,5 раз быстрее ! dBase5test.exe - размер файла 842752 байт, программа в памяти занимает 1,3 - 1,6 Мб Две тестовые базы - Recno: 2525/127500 На SSD HDD загрузка проца 30% - время счета 04 minute 11 seconds На обычном HDD загрузка проца 1,6% - время счета 59 minute 58 seconds Вот такие результаты...

Dima: Andrey пишет: Если база располагается на SSD - то загрузка проца возрастает и тест-dBase5test.exe проходит в 14,5 раз быстрее ! Ты еще на RAM диске запусти , будет еще быстрее ;) Ориентироваться надо на обычные HDD.

a_sidorov: Похоже дело в DBCOMMIT() на каждой записи, если вынести его за цикл, то время уменьшается в несколько десятков раз

Andrey: Dima пишет: Ты еще на RAM диске запусти Да забыл...

Andrey: Вот прислал мне a_sidorov модифицированную программу. Спасибо БОЛЬШОЕ ! Это то что нужно... Главное понимать что и когда делать... По производительности, предыдущий тест: CPU: Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz [~3504 MHz] Free RAM: 2 097 151 OS: Windows Windows Vista Professional 6.02.9200 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 00 seconds ( Recno: 2525/127500 ) Write test base - 00 hour 59 minute 59 seconds The total test time ---> 00 hour 59 minute 59 seconds Модифицированный тест, на этом же компе: Create/Open Test.dbf - 00 hour 00 minute 00 seconds ( Recno: 2525/127500 ) Write test base - 00 hour 00 minute 08 seconds The total test time ---> 00 hour 00 minute 08 seconds Результат классный !!! Жалко только опять примера нет на МНОГОПОТОКОВУЮ обработку базы.... Исходник и пример здесь - http://files.mail.ru/ADB643696C364CC983BE1BC5FE1B9D3F

Dima: Andrey пишет: Результат классный !!! The third example of measuring the speed of processing database for [x]Harbour Copyright 2013 Verchenko Andrey <verchenkoag@gmail.com> Russia, Dmitrov --------------------------------------------------------------------------- CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz [~3011 MHz] Free RAM: 578 452 OS: Windows XP Professional 5.01.2600 Service Pack 2 Development: xHarbour build 1.0.0 Intl. (SimpLex) - Borland C++ 5.5.1 Multi Thread: No --------------------------------------------------------------------------- Create/Open Test.dbf - 00 hour 00 minute 46 seconds ( Recno: 2525/127500 ) Write test base - 00 hour 01 minute 09 seconds The total test time ---> 00 hour 01 minute 56 seconds

Andrey: Dima пишет: CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz [~3011 MHz] Free RAM: 578 452 OS: Windows XP Professional 5.01.2600 Service Pack 2 Значит у моих юзеров тоже будет летать ... Спасибо Дима !

Dima: Andrey пишет: Жалко только опять примера нет на МНОГОПОТОКОВУЮ обработку базы.... ты сам ответил ;) Andrey пишет: Это то что нужно... Главное понимать что и когда делать.. Просто надо сделать оптимальный алгоритм. Она , многопоточность тут скорее всего и не нужна.

Andrey: Dima пишет: Просто надо сделать оптимальный алгоритм. Исправил (убрал DBCOMMIT) у себя в расчетах, вынес в конец обработки. Перерасчет всех абонентов при 70000 абонентов вместо 1ч 20мин. стал занимать 17 минут.... А у других базы еще меньше... Спасибо БОЛЬШОЕ ВСЕМ за помощь !

Andrey: PSP пишет: Не спеши... ))) Я там подправил сообщение. Проверь функцию. update: Проверил в Харборе WIN_OSVersionInfo(). Нормально работает. WIN_OSVersionInfo()[ 2 ] на 7-ке выдало "1". Беру winos.prg из хХарбора 1.2.3 SVN, вставляю в свой проект на 1.2.1, запрашиваю OS_ISWIN8() и получаю .F. (на своей Win8) Как бы им туда сообщить....

Dima: Andrey пишет: Беру winos.prg из хХарбора 1.2.3 SVN, вставляю в свой проект на 1.2.1, запрашиваю OS_ISWIN8() и получаю .F. (на своей Win8) Я бы пересобрал проект под 1.2.3 в этом случае если очень надо. Голый номер брать исходники из новых версий и вставлять в старые версии как правило. Хотя конечно что брать и куда вставлять ...смотреть надо Andrey пишет: Беру winos.prg из хХарбора 1.2.3 SVN, вставляю в свой проект на 1.2.1 Это почти тоже что вставить этот исходник ну скажем в хХарбор 1.0.0 и попытаться получить положительный результат.

PSP: Не знаю, как в хэХарборе, а в просто Харборе эти функции описаны в \contrib\hbwin\win_os.c К примеру, [pre2]HB_FUNC( WIN_OSIS8 ) { OSVERSIONINFO osvi; getwinver( &osvi ); hb_retl( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2 ); } [/pre2]

Andrey: Dima да бесполезно пересобирать... смотри что там в исходнике написано: PSP пишет: Не знаю, как в хэХарборе Там в исходнике winos.prg написано: #pragma BEGINDUMP #if defined(HB_OS_WIN) && (!defined(__RSXNT__)) && (!defined(__CYGWIN__)) ............... HB_FUNC( OS_ISWIN8 ) { OSVERSIONINFO osvi; getwinver( &osvi ); hb_retl( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 2 ); } #else ............. HB_FUNC( OS_ISWIN8 ) { hb_retl( 0 ) ; } #endif

Andrey: Вот пример по делу, мультипотоковая индексация БД для Харбора (под хХарбор не делал). Тема примера: возврат значений (переменные cResultError и nResultIndexFile) после выполнения потока. Большое СПАСИБО alkresin ! Без него бы не сделал ! Может кому и пригодиться. //////////////////////////////////////////////////////////////////////////////// // // Index_MT.prg.prg // // Copyright: // Verchenko Andrey <verchenkoag@gmail.com>, (c) 2013. All rights reserved. // An example of Returning values from a stream in the Harbor. // //////////////////////////////////////////////////////////////////////////////// #include "ord.ch" #include "hbthread.ch" #define CLRF Chr( 13 ) + Chr( 10 ) #define PROGRAM " Returning values from a stream in the Harbor" #define COPYRIGHT " Copyright 2013 - http://clipper.borda.ru" #define NUMBER_DATABASE_RECORDS 2500 Static nResultIndexFile, cResultError, nTimerCount FUNCTION MAIN() LOCAL cLogFile := SUBSTR( HB_ArgV(0), 1, RAT(".", HB_ArgV(0) ) ) + "log" LOCAL nTimeStart, nTime2, nTime1, aRec, cStr, cError, aParDbf, threadA REQUEST DBFCDX RddSetDefault( 'DBFCDX' ) SETCURSOR(0) SETMODE(25,80) SETCOLOR("11/1") CLEAR SCREEN MyInfo(cLogFile) nTimeStart := SECONDS() IF !hb_mtvm() ALERT("No support for multi-threading !" + CRLF + CRLF + ; "Collect program with the - /mt !" + CRLF ) QUIT ENDIF // create test base nTime1 := SECONDS() ? ; ? "Create/Open Dbf - " aRec := Create_Test_DBF() ?? MyTime(SECONDS(), nTime1) + "( Recno: "+LTRIM(STR(aRec[1]))+"/"+LTRIM(STR(aRec[2]))+"/"+LTRIM(STR(aRec[3]))+" )" STRFILE("Create/Open Dbf - "+MyTime(SECONDS(), nTime1)+"( Recno: "+LTRIM(STR(aRec[1]))+"/"+LTRIM(STR(aRec[2]))+"/"+LTRIM(STR(aRec[3]))+" )"+CLRF, cLogFile, .T.) ? nTime1 := SECONDS() aParDbf := { {"test2.dbf","ABONENT1","test20.cdx"} , ; {"test1.dbf","DOGOVOR1","test10.cdx"} , ; {"test3.dbf","ABONENT2","test30.cdx"} } cResultError := "" // текст ошибки при индексации nResultIndexFile := 0 // результат индексации nTimerCount := 0 // показ таймера (сек.) индексации // as an example - MassivParametrovBazy, logfiles, Coordinates YX hb_threadDetach( hb_threadStart( @MyIndexFile() , aParDbf, cLogFile, ROW(), COL() ) ) // After creating a stream run timer associated with the procedure DO WHILE !TimerProc() ENDDO STRFILE("Indexing all databases over - "+MyTime(SECONDS(), nTime1)+CLRF, cLogFile, .T.) IF LEN(cResultError) > 0 ALERT("Errors when indexing database !;;"+cResultError ) ENDIF @ MAXROW()-1, 0 SAY " Return @MyIndexFile() -> nResultIndexFile = " + LTRIM(STR(nResultIndexFile)) COLOR("14/1") @ MAXROW() , 0 SAY PADC(" End work ",MAXCOL()+1,"-") COLOR("15/4") INKEY(0) CLOSE ALL RETURN NIL //////////////////////////////////////////////////////////////////////////////// Function TimerProc Local nSec := Seconds() @ MAXROW(), 5 SAY Str(nTimerCount++) COLOR("15/4") INKEY(1) IF nResultIndexFile != 0 // Hence, the thread has terminated, to inform about the result of his work // Close timer Return .T. ENDIF Return .F. //////////////////////////////////////////////////////////////////////////////// FUNCTION MyIndexFile(aParDbf, cLogFile, nY, nX ) LOCAL nI, nJ, nG, cStr, nLastRecno, nY2, nX2 LOCAL cIndexTo, cFilterTo, cFileIndex, nKolRecords LOCAL bErrHandler, cDbfName, cDbfAlias, nErrDos cStr := CLRF + CLRF + PADC("",75,"-") + CLRF cStr += PADC("Indexing databases in a separate thread",75) + CLRF cStr += PADC("",75,"-") + CLRF + CLRF STRFILE(cStr, cLogFile, .T.) FOR nI := 1 TO LEN(aParDbf) cDbfName := aParDbf[nI,1] cDbfAlias := aParDbf[nI,2] cFileIndex := aParDbf[nI,3] @ nY + nI*2, nX SAY " Use Dbase - " + cDbfName bErrHandler := ErrorBlock( { | VAR | BREAK( VAR ) } ) BEGIN SEQUENCE USE ( cDbfName ) Alias ( cDbfAlias ) EXCLUSIVE NEW RECOVER cStr := " ->-> ERROR! DB-" + cDbfName + " busy with another task !" @ nY + nI*2, nX+26 SAY cStr STRFILE(cStr, cLogFile, .T.) nResultIndexFile := -2 // Unable to open the database cResultError += cStr + ";" RETURN NIL END SEQUENCE ErrorBlock( bErrHandler ) nKolRecords := LASTREC() cIndexTo := "NN" cFilterTo := "!DELETED()" IF FILE (cFileIndex) nErrDos := DELETEFILE( cFileIndex ) IF nErrDos # 0 cStr := " ->-> ERROR ("+LTrim( Str( nErrDos ) )+") ! Access denied to delete a file " + cFileIndex + " !" @ nY + nI*2, nX+26 SAY cStr STRFILE(cStr, cLogFile, .T.) nResultIndexFile := -3 // Unable to delete the index file cResultError += cStr + ";" RETURN NIL ENDIF ENDIF @ nY + nI*2, nX+26 SAY "Index base - " + cFileIndex + " -> " ; nY2 := ROW() ; nX2 := COL() INDEX ON &cIndexTo TO (cFileIndex) ; EVAL SAY_PROC( nY2, nX2, RECNO(), nKolRecords) ; EVERY nKolRecords / 10 FOR &cFilterTo NEXT nResultIndexFile := 1 // No error - on the basis of the current RETURN NIL //////////////////////////////////////////////////////////////////////////////// FUNCTION Create_Test_DBF() LOCAL aDbf1, aDbf2, nI, nJ, nK, n1, n2, cStr, nNN, nID := 100 LOCAL cTable2 := "test2.dbf", cTable1 := "test1.dbf", cTable3 := "test3.dbf" LOCAL cPathFolder := hb_CurDrive() + ":\" + CurDir() + '\' LOCAL nY := ROW(), nX := COL() aDbf2 := { { "FIO" , "C", 35, 0 }, ; { "LastName" , "C", 20, 0 }, ; { "YES" , "N", 2, 0 }, ; { "NN" , "N", 8, 0 }, ; { "NNN" , "N", 8, 0 }, ; { "KTARIF" , "N", 2, 0 }, ; { "SKIDKA" , "N", 3, 0 }, ; { "NDOG" , "C", 12, 0 }, ; { "KOkrug" , "N", 6, 0 }, ; { "KDez" , "N", 6, 0 }, ; { "KCity" , "N", 6, 0 }, ; { "KStreet" , "N", 6, 0 }, ; { "cNumHOUSE", "C", 10, 0 }, ; { "NumKorp" , "N", 4, 0 }, ; { "NumPodezd", "N", 2, 0 }, ; { "cNumKvar" , "C", 10, 0 }, ; { "KStDogov" , "N", 2, 0 }, ; { "KVid_to" , "N", 2, 0 }, ; { "KVidOpl" , "N", 2, 0 }, ; { "KPVidOpl" , "N", 2, 0 }, ; { "KFili" , "N", 2, 0 }, ; { "KFiliDop" , "N", 2, 0 }, ; { "KFiliDsp" , "N", 2, 0 }, ; { "DateRas1" , "D", 8, 0 }, ; { "KUCompany", "N", 2, 0 }, ; { "KEIRC" , "N", 5, 0 }, ; { "KTipZak" , "N", 3, 0 }, ; { "KZakaz" , "N", 3, 0 }, ; { "RC_abon" , "C", 8, 0 }, ; { "RC_abon0" , "C", 8, 0 }, ; { "RC_abon3" , "C", 8, 0 }, ; { "RC_abon4" , "C", 8, 0 }, ; { "RC_NEW18" , "C", 18, 0 }, ; { "Logik" , "L", 1, 0 } } // aadd field memo AADD( aDbf2, { "MEMOTEST" , "M", 10, 0 } ) aDbf1 := { { "FIOST" , "C", 35, 0 }, ; { "LastNam2" , "C", 20, 0 }, ; { "Age" , "N", 3, 0 }, ; { "Date" , "D", 8, 0 }, ; { "Rate" , "N", 6, 2 }, ; { "DateRas2" , "D", 8, 0 }, ; { "DateDog" , "D", 8, 0 }, ; { "NN" , "N", 8, 0 }, ; { "NDOG" , "C", 12, 0 }, ; { "KOkrug" , "N", 6, 0 }, ; { "KDez" , "N", 6, 0 }, ; { "KCity" , "N", 6, 0 }, ; { "KStreet" , "N", 6, 0 }, ; { "cNumHOUSE", "C", 10, 0 }, ; { "NumKorp" , "N", 4, 0 }, ; { "NumPodezd", "N", 2, 0 }, ; { "cNumKvar" , "C", 10, 0 }, ; { "KStDogov" , "N", 2, 0 }, ; { "KVid_to" , "N", 2, 0 }, ; { "KVidOpl" , "N", 2, 0 }, ; { "KPVidOpl" , "N", 2, 0 }, ; { "KFili" , "N", 2, 0 }, ; { "KFiliDop" , "N", 2, 0 }, ; { "KFiliDsp" , "N", 2, 0 }, ; { "DateRas1" , "D", 8, 0 }, ; { "KUCompany", "N", 2, 0 }, ; { "KEIRC" , "N", 5, 0 }, ; { "KTipZak" , "N", 3, 0 }, ; { "KZakaz" , "N", 3, 0 }, ; { "MEMO2" , "M", 10, 0 } } IF !FILE(cTable1) // if there is no database, then create it DBCreate( cTable1, aDbf1 ) USE ( cTable1 ) ALIAS DOGOVOR NEW DBCreate( cTable2, aDbf2 ) USE ( cTable2 ) ALIAS ABONENT NEW SELECT DOGOVOR FOR nI := 1 TO NUMBER_DATABASE_RECORDS @ nY, nX + 3 SAY "Recno:"+LTRIM(STR(nI)) SELECT DOGOVOR APPEND BLANK n1 := hb_RandomInt( 80 ) n2 := hb_RandomInt( 50 ) REPLACE FIELD->Age WITH n1, ; FIELD->Date WITH Date() - 365 * n2 + n1, ; FIELD->Rate WITH 56.5 - n1 / 2 REPLACE FIELD->FIOST WITH "Dog" + Chr( 64 + n2 ) + PadL( nI, 10, '0' ), ; FIELD->LastNam2 WITH "MyB" + Chr( 70 + n2 ) + PadL( nI, 12, '0' ) FIELD->NN := nI FIELD->NDOG := "D"+LTRIM(STR(nI))+"/"+LTRIM(STR(n2)) FIELD->KOkrug := n1 FIELD->KDez := n2 FIELD->KCity := n1-8 FIELD->KStreet := n2-9 FIELD->cNumHOUSE:= LTRIM(STR(n1-n2))+Chr( 60 + n2 ) FIELD->NumKorp := IIF( nI % 30 == 0 , 1 , 0 ) FIELD->NumPodezd:= 0 FIELD->KStDogov := 4 FIELD->KVid_to := 1 FIELD->KVidOpl := 2 FIELD->KPVidOpl := 3 FIELD->KFili := 1 FIELD->KFiliDop := 1 FIELD->KFiliDsp := 2 FIELD->DateRas1 := Date() - 365 * n2 + n1 FIELD->KUCompany:= 10 FIELD->KEIRC := 11 FIELD->KTipZak := 12 FIELD->KZakaz := 13 FOR nJ := 1 TO 51 // number of subscribers nID := nID + nJ + 1 SELECT ABONENT APPEND BLANK FIELD->NN := nI FIELD->cNumKvar := LTRIM(STR(nJ)) FIELD->NNN := nID++ FIELD->KTARIF := IIF( nI % 800 == 0 , 0 , n1/10 ) FIELD->SKIDKA := IIF( nI % 300 == 0 , 100 , 0 ) cStr := PADL(ALLTRIM(STR(RECNO())),8,"0") FIELD->RC_abon:= IIF( nI % 150 == 0 , "", cStr ) IF nI % 500 == 0 cStr := PADL(ALLTRIM(STR(RECNO()-11)),8,"0") FIELD->RC_abon:= cStr ENDIF FIELD->FIO := "Abon" + Chr( 64 + n2 ) + PadL( nI, 20, '0' ) FIELD->MEMOTEST := "test: " + ALLTRIM( STR(nI) ) IF nJ == 49 // emulation error FIELD->NN := 0 ENDIF IF nJ == 50 // emulation error FIELD->NN := nI+2000 ENDIF IF nJ == 51 // emulation recno deleted DBDELETE() ENDIF NEXT // emulation recno deleted IF nI % 100 == 0 SELECT DOGOVOR APPEND BLANK DELETE ENDIF NEXT SELECT DOGOVOR nI := LASTREC() CLOSE DOGOVOR SELECT ABONENT nJ := LASTREC() CLOSE ABONENT FILECOPY (cPathFolder + cTable2, cPathFolder + cTable3) FILECOPY (cPathFolder + "test2.fpt", cPathFolder + "test3.fpt") nK := nJ ELSE USE ( cTable1 ) NEW nI := LASTREC() USE USE ( cTable2 ) NEW nJ := LASTREC() USE USE ( cTable3 ) NEW nK := LASTREC() USE ENDIF RETURN {nI,nJ,nK} //////////////////////////////////////////////////////////////////////////////// Function MyInfo(cLogFile) LOCAL aStr := {}, nI AADD( aStr , PROGRAM ) AADD( aStr , COPYRIGHT ) AADD( aStr , PADC("",75,"-") ) AADD( aStr , " Free RAM: " + ALLTRIM(TRANSFORM(memory(0),"999 999 999")) ) AADD( aStr , " OS: " + OS() ) AADD( aStr , " Development: " + Version() + " - " + hb_compiler() ) AADD( aStr , " Multi Thread: " + IIF( hb_mtvm()==.Y., "Yes", "No" ) ) AADD( aStr , PADC("",75,"-") ) STRFILE("", cLogFile, .F.) FOR nI := 1 TO LEN(aStr) ? aStr[nI] STRFILE(aStr[nI]+CLRF, cLogFile, .T.) NEXT RETURN NIL //////////////////////////////////////////////////////////////////////////////// // Returns: a string of the past tense FUNCTION MyTIME(nTime2, nTime1) LOCAL cTime, cRet cTime := SECTOTIME(nTime2 - nTime1) cRet := SUBSTR(cTime,4,2)+" minute " + ; SUBSTR(cTime,7,2)+" seconds " RETURN cRet //////////////////////////////////////////////////////////////////////////////// FUNCTION SAY_PROC( y, x, nRecno, nKolRecords ) DevPos( y, x+3 ) DevOutPict( Int( nRecno / nKolRecords*100 ), "999%" ) INKEY(0.5) RETURN .T.

nick_mi: Спасибо за пример Андрей! Но в программе вкралась ошибка. По Невнимательности собрал программу без -mt и программа вылетела с ошибкой нет переменной CRLF. У тебя в программе определена #define CLRF, и при правильной работе именно она используется, а при неправильной сборке задействована CRLF для формирования сообщения.

Andrey: nick_mi пишет: У тебя в программе определена #define CLRF, и при правильной работе именно она используется, Ну уж не досмотрел....

nick_mi: Бывает!

Andrey: Возвращаюсь опять к потокам. Где считается база быстрей (или одинаково) в потоке или в основной программе ? Т.е. создаю отдельный поток для расчёта по базе, а основную программу оставляю в ожидание окончания потока. По времени как будет ? Одинаково или нет ? И еще вопрос: можно ли в отдельном потоке создавать окна (МиниГуи), а после выполнения потока просто оставить не убитым. Что будет ?

Alex_Cher: Andrey пишет: Исходник и сама программа здесь - http://files.mail.ru/5A8E598290604D31955459BEFBDF3FD3 Ошибка 404 ... не могу скачать

Andrey: Alex_Cher пишет: .. не могу скачать А какую программу скачиваете ? Я может убил её давно...

Dima: Andrey пишет: Я может убил её давно... Так объем облака 100 Гб ....экономишь ?

Andrey: Dima пишет: Так объем облака 100 Гб ....экономишь ? Старые примеры иногда переделываю...

Alex_Cher: Dima пишет: Так объем облака 100 Гб ....экономишь ? Нет мужики это я лохонулся ... тема интересная а сроки выкладки сообщения не посмотрел ...



полная версия страницы