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

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

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

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

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



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