|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Одновременное выполнение процедур/функций
Столкнулся я с задачей, когда времени на ее решение (программного) нет! Суть такова : Есть около 20-30 процедур, которые перебирают уйму информации. На все это уходит много времени, ибо данных много(очень много)!
Возможно ли выполнять несколько процедур одновременно??? |
#2
|
||||
|
||||
Потоки не подходят?
Что делать, когда сломался комп: 1. Если вы юзер - делать ноги. 2. Если ремонтник - делать деньги. 3. Если вы программист - делать вид, что так было задумано. |
#3
|
|||
|
|||
Это пример процедур, которые долго работают. Пока их только 13 и все они имеют приблизительно одинаковую структуру.
Код:
Procedure FirstVed_add_2; Var i,j:integer; begin j:=j-8; for i:=1 to 15 do begin j:=j+8; Setrange(1,'Q'+inttostr(125-j),''); Setrange(1,'Q'+inttostr(126-j),''); Setrange(1,'W'+inttostr(125-j),''); Setrange(1,'W'+inttostr(126-j),''); Setrange(1,'W'+inttostr(121-j),''); Setrange(1,'W'+inttostr(122-j),''); Setrange(1,'X'+inttostr(121-j),''); Setrange(1,'X'+inttostr(122-j),''); SetBorderRange(1,'S'+inttostr(125-j)+':V'+inttostr(125-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'S'+inttostr(126-j)+':V'+inttostr(126-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(125-j)+':Y'+inttostr(125-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'S'+inttostr(126-j)+':Y'+inttostr(126-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(121-j)+':Y'+inttostr(121-j),xlEdgeTop,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(121-j)+':Y'+inttostr(121-j),xlEdgeLeft,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(121-j)+':Y'+inttostr(121-j),xlEdgeRight,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(122-j)+':Y'+inttostr(122-j),xlEdgeLeft,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(122-j)+':Y'+inttostr(122-j),xlEdgeRight,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(123-j)+':Y'+inttostr(123-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(123-j)+':Y'+inttostr(123-j),xlEdgeLeft,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'X'+inttostr(123-j)+':Y'+inttostr(123-j),xlEdgeRight,xlDashDot,xlThin,0,rgb(255,255,255)); end; j:=-8; for i:=1 to 15 do begin j:=j+8; Setrange(1,'F'+inttostr(125-j),''); Setrange(1,'F'+inttostr(126-j),''); Setrange(1,'L'+inttostr(125-j),''); Setrange(1,'L'+inttostr(126-j),''); Setrange(1,'M'+inttostr(121-j),''); Setrange(1,'M'+inttostr(122-j),''); SetBorderRange(1,'H'+inttostr(125-j)+':K'+inttostr(125-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'H'+inttostr(126-j)+':K'+inttostr(126-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(125-j)+':N'+inttostr(125-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(126-j)+':N'+inttostr(126-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(121-j)+':N'+inttostr(121-j),xlEdgeTop,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(121-j)+':N'+inttostr(121-j),xlEdgeLeft,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(121-j)+':N'+inttostr(121-j),xlEdgeRight,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(122-j)+':N'+inttostr(122-j),xlEdgeLeft,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(122-j)+':N'+inttostr(122-j),xlEdgeRight,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(123-j)+':N'+inttostr(123-j),xlEdgeBottom,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(123-j)+':N'+inttostr(123-j),xlEdgeLeft,xlDashDot,xlThin,0,rgb(255,255,255)); SetBorderRange(1,'M'+inttostr(123-j)+':N'+inttostr(123-j),xlEdgeRight,xlDashDot,xlThin,0,rgb(255,255,255)); end; end; Вот процедура, которая через потоки вызывает необходимые процедуры: Код:
Procedure FirstVed; Var i,j:integer; h1:cardinal; begin if strtoint(vidor_vdm_form.label11.Caption)Ю0 then begin CreateThread(nil,0,@FirstVed_add_1,nil,0,h1) ; .................. CreateThread(nil,0,@FirstVed_add_13,nil,0,h1) ; end; end; И процедура, которая все это вызывает: Код:
if not CreateExcel then exit; j:=0; jj:=0; OpenWorkBook(getcurrentdir+'\ADP_VED\template_1.xls'); for i:=1 to vidor_vdm_form.listbox1.Items.Count-1 do begin if i mod 2=1 then begin j:=j+8; SetRange(1,'G'+inttostr(j),vidor_vdm_form.listbox1.Items.Strings[i]); SetRange(1,'G'+inttostr(j+1),vidor_vdm_form.listbox2.Items.Strings[i]); end; if i mod 2=0 then begin jj:=jj+8; SetRange(1,'R'+inttostr(jj),vidor_vdm_form.listbox1.Items.Strings[i]); SetRange(1,'R'+inttostr(jj+1),vidor_vdm_form.listbox2.Items.Strings[i]); end; end; FirstVed; //процедура, работающая с потоками VisibleExcel(true); PrintPreviewEx; SaveWorkBookAs(getcurrentdir+'\VDM\'+datetostr(date)+'.vdm'); CloseWorkBook; CloseExcel; Результат работы выполнения во вложении: |
#4
|
|||
|
|||
При пошаговом выполнении программы, ошибка вылетает на
Код:
CreateThread(nil,0,@FirstVed_add_1,nil,0,h1) ; P.S. Может я неправильно сделал/оформил/написал сами потоки??? Да, и при использовании процедур в процедуре FirstVed без потоков, то все работает без проблем, но очень долго. Надеюсь на помощь! Заранее спасибо! |
#5
|
|||
|
|||
Создание потоков не увеличит скорость выполнения процедур и функций. Надо оптимизировать.
|
#6
|
|||
|
|||
to ART
Да, я с тобой согласен, что процедура/функция не будет работать быстрее из-за того, что она будет выполняться в отдельном протоке! Но!!! Вопрос ведь заключается в другом... У меня таких процедур(практически с одинаковой структурой) пока только 13, а в конечном итоге должно быть от 20 до 30. И ведь если все эти процедуры будут выполняться через COM в многопоточности(Multithreaded(MTA)), то это существенно увеличит время выполнения. Ломал я голову, лазил по инэту и нашел интересную статейку, в которой расказывается про однопоточность и многопоточность... В ней рассказывается, что при работе с COM (с потоками) необходимо инициализировать отдельный поток, т.к. COM по умолчанию(да и Delphi нас снабжает модулем ComObj.pas, который позволяет работать только в однопоточном режиме...) работает только с одним потоком информации(грубо говоря очередь выстраивается )... Теперь если посмотреть дальше, то не трудно понять что дополнительные потоки необходимо инициализировать при помощи такого кода: Код:
CoInitializeEx (NIL, COINIT_MULTITHREADED); //создаем дополнительный поток //выполнение созданного потока CoUninitialize; //Даем понять COM'у , что этот поток выполнил все что от него требуется и его можно отключать, для последующего(если требуется) повторного запуска. Для использования CoInitializeEx и CoUninitialize необходимо подключать модуль ActiveX. Что из этого происходит: Инициализвация(создание) новго потока проходит без вопросов, первы поток начинает выполнение, и после того, как инициализируется втрой - COM отключается от программы и пишет "не инициализирован CoInitializeEx" Так вот НАДЕЮСЬ, что загвоздка осталась именно в инициализации потока для MTA. Написал код для STA. Вот что получилось: Код:
TSTAAutoObjectFactory = class(TAutoObjectFactory, IClassFactory) function CreateInstance; end; TSTAThread = class (TThread) procedure Execute; override; end; // function TSTAAutoObjectFactory.CreateInstance; begin Создает TSTAThread, заставляет поток STA создать затребованный объект,и ждет, пока поток STA успешно создаст объект, после чего возвращает созданный экземпляр в качестве результата этого метода end; Выполнение: Код:
procedure TSTAThread.Execute; begin // Вход в STA CoInitializeEx (NIL, COINIT_APARTMENTTHREADED); // Создает экземпляр, затребованный TSTAAutoObjectFactory; // Сигнализирует потоку TSTAAutoObjectFactory.CreateInstance, что // экземпляр теперь доступен // Вход в цикл сообщений STA CoUninitialize; // Выход из STA end; Работает без вопросов! Все отлично! Но это STA(однопоточность)... Стоит сделать многопоточность - сразу вылетает ошибка, что потоки не инициализированы! Подскажите, что я не правильно делаю!!!??? |
#7
|
|||
|
|||
Если как-то заумно написал, то вкратце это звучит так:
Необходимо выполнять в COM(в данном случае работа с Excel) несколько потоков ОДНОВРЕМЕННО!!! Надеюсь на помощь... |
#8
|
|||
|
|||
Пробовал использовать эти процедуры для создания списка компьютеров в отдельном потоке (уж очень надолго вешает программу при однопоточности)
При создании формы создаю отдельный поток: CoInitializeEx (NIL, COINIT_MULTITHREADED); периодически опрашиваю сеть: CreateThread(nil, 0, @UpdateHostList, nil, 0, h1); После такого опроса возникает ошибка при переходе по страницам PageControl "Недопустимый дескриптор окна" и ошибка при попытке закрыть программу. Мож кто скажет, как правильно использовать эти три процедуры(в каком порядке), чтобы избежать ошибки: CoInitializeEx, CreateThread, CoUninitialize. |
#9
|
|||
|
|||
Цитата:
Если баотаешь с Excel, то создавай временный массив работай с ним, а результат кидай через Range. |
#10
|
|||
|
|||
Phedor
Если я правильно понял, то имеешь ввиду заливать данные матрицей. Это без вопросов. В конечном итоге я так и сделал, но самое противное, что после заполнения данными начинают перерисовываться ячейки (т.е. чтобы она была с контурами, перечеркнутая и т.д.). А матрицей не получится такое организовать, т.к. разных "видов" ячеек до 15. Решил я проблему очень банально. Создал шаблоны с разными видами ячеек и перед заполнением данными открываю тот шаблон, который мне нужен. Конечно это не выход в данной ситуации, но мне ничего не оставалось, т.к. с многопоточность я не смог разобраться, хотя очень хочу! |
#11
|
|||
|
|||
Цитата:
2. Долго это конечно, но проверте не показываете ли вы саму перерисовку. Сначала создаем соединение, выводим, а потом уже показываем. Проверял, если сначала Show сделать, а потом рисовать примерно в 15 раз медленее получается. 3. Многопоточность. Попробуйте выводить разные блоки инфы в разных потоках. В главном только открытие и закрытие COM-сессии. |
#12
|
|||
|
|||
Phedor
1. Не знал. 2. Так и делаю. 3. У меня и есть разные блоки в разных потоках, но все-равно СОМ меня не пускает! Принцип построения алгоритма: 1.Основной поток, отвечающий за открытие/закрытие/отображение Excel 2. Выполняется основной код, разбитый на блоки (разные потоки), которых 32. Первый поток заполняет данными лист, второй, третий, ..., двадцать седьмой - разрисовывает ячейки. Разрисовывать надо очень много, поэтому столько потоков на отрисовку... После рисования и заполнения данными - 28,29,30,31,32 потоки строят диаграммы на основании введенных данных... ну их соответственно 5. Я объяснил сухо конечно, но у меня нет возможности показать код, т.к. он дома, а я еще неделю в командировке! Когда мне ставили задачу, то необходим был именно Excel. Мол так удобнее просматривать, чем в стринггриде, да и примитивные диаграммы(TChar'ты) выглядят плохо... Короче нужен Excel. Фух... написал... |
#13
|
|||
|
|||
Проблема при использовании потоков
Нашел бок при использовании потоков.
При выделении памяти в отдельном потоке(с последующим ее освобождением) происходит потеря связи приложения с окнами. ("Недопустимый дескриптор окна" и др.) Сначало проявилось на стандартной функции TList.add(Item: Pointer): integer. Пробовал сделать свой клас-список, не помогло, тот же бок. Стоит убрать работу с памятью - и все ОК. Кто-нидь скажет: ЭТО чем-то лечится? |