![]() |
|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
![]() Прошу у вас помощи.
Суть такова: Создаются 5 потоков с таким вот кодом Код:
procedure Searcher.Execute; var i: integer; begin FHTTPS := THTTPSend.Create; FLIST := TStringList.Create; FHTML := TStringList.Create; FRegExp := TRegExpr.Create; try for i := 0 to 5 do begin setheaders; FHTTPS.HTTPMethod('GET', URL + inttostr(i)); begin FHTML.Clear; FHTML.LoadFromStream(FHTTPS.Document, TEncoding.UTF8); if pos('<steamID64>', FHTML.Text) > 0 then begin FRegExp.Expression := '<steamID64>(.*?)</steamID64>'; if FRegExp.Exec(FHTML.Text) then repeat FLIST.Add(FRegExp.Match[1]); until not FRegExp.ExecNext; end; end; end; finally FreeAndNil(FHTTPS); FreeAndNil(FLIST); FreeAndNil(FHTML); FreeAndNil(FRegExp); end; end; Проблема: Дело в том , что эти 5 потоков выполняют одно и тоже действие. Вопрос: Как сделать так , чтобы действия не повторялись а улучшилась скорость? То есть , если всё делать в один поток , работа будет медленной , я специально сделал многопоток чтобы улучшить скорость , вообщем создаётся 5 потоков но действие повторяется , мне нужно чтобы эти 5 потоков выполняли одно действие только быстро , то есть как один поток , но при этом скорость была больше. Вот весь код: Код:
type Searcher = class(TThread) private FHTTPS: THTTPSend; FLIST, FHTML: TStringList; FRegExp: TRegExpr; protected procedure Execute; override; procedure setheaders; public end; var Form1: TForm1; URL: string; Th: array [0 .. 5] of TThread; implementation {$R *.dfm} { Searcher } procedure Searcher.Execute; var i: integer; begin FHTTPS := THTTPSend.Create; FLIST := TStringList.Create; FHTML := TStringList.Create; FRegExp := TRegExpr.Create; try for i := 0 to 5 do begin setheaders; FHTTPS.HTTPMethod('GET', URL + inttostr(i)); begin FHTML.Clear; FHTML.LoadFromStream(FHTTPS.Document, TEncoding.UTF8); if pos('<steamID64>', FHTML.Text) > 0 then begin FRegExp.Expression := '<steamID64>(.*?)</steamID64>'; if FRegExp.Exec(FHTML.Text) then repeat FLIST.Add(FRegExp.Match[1]); until not FRegExp.ExecNext; end; end; end; finally FreeAndNil(FHTTPS); FreeAndNil(FLIST); FreeAndNil(FHTML); FreeAndNil(FRegExp); end; end; procedure TForm1.Button1Click(Sender: TObject); var Threads: integer; begin URL := Edit1.Text + '/memberslistxml/?xml=1&p='; for Threads := 0 to 4 do begin Th[Threads] := Searcher.Create; Th[Threads].FreeOnTerminate := true; end; end; procedure Searcher.setheaders; begin with FHTTPS do begin Document.Clear; Headers.Clear; KeepAlive := true; Headers.Add('Accept: */*'); Headers.Add('Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4'); Headers.Add('Accept-Charset: utf-8;q=0.7,*;q=0.3'); UserAgent := 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36'; end; end; Последний раз редактировалось Avenger15, 30.09.2015 в 22:30. |
#2
|
|||
|
|||
![]() Кажется, вы чего-то не понимаете в потоках. Точнее в их применении.
Фактически, можно говорить о том, что поток - это отдельный процесс. Просто они выполняются в одном адресном пространстве, так что легче организовать взаимодействие между ними. Однако, они остаются все-таки разными процессами. Т.е. если потоку, например, нужно работать с COM, то каждый поток должен инициализировать COM-подсистему. В вашем конкреном случае я вижу только одну возможность (признаюсь, смотрел не очень внимательно). Вот там, где у вас есть цикл от 1 до 5, каждый поток делает совсем одно и то же. Можно сделать так, что бы каждый поток отрабатывал только одну из цифр (т.е. разные урлы). Тогда каждый поток будет выполнять свою задачу, не пересекаясь по данным c другими. Что будет примерно в 5 раз быстрее (ну не в 5 на самом деле, где-то, ориентировочно, в 3, и то, если сама операция достаточно длительная). |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Avenger15 (01.10.2015)
|
#3
|
|||
|
|||
![]() Цитата:
Цитата:
Последний раз редактировалось Avenger15, 01.10.2015 в 00:13. |
#4
|
|||
|
|||
![]() 1) перенести переменную i из метода Execute в поля класса Searcher.
2) из метода Execute убрать цикл. 3) Button1Click переписать так Код:
procedure TForm1.Button1Click(Sender: TObject); var Threads: integer; begin URL := Edit1.Text + '/memberslistxml/?xml=1&p='; for Threads := 0 to 4 do begin Th[Threads] := Searcher.Create(True); Th[Threads].i := Threads; Th[Threads].FreeOnTerminate := true; Th[Threads].Resume(); end; end; |
Этот пользователь сказал Спасибо icWasya за это полезное сообщение: | ||
Avenger15 (01.10.2015)
|
#5
|
|||
|
|||
![]() Цитата:
Код:
type Searcher = class(TThread) private FHTTPS: THTTPSend; FLIST, FHTML: TStringList; FRegExp: TRegExpr; protected procedure Execute; override; procedure sync; procedure setheaders; public i: integer; end; var Form1: TForm1; URL: string; Th: array [0 .. 5] of TThread; implementation {$R *.dfm} { Searcher } procedure Searcher.Execute; begin FHTTPS := THTTPSend.Create; FLIST := TStringList.Create; FHTML := TStringList.Create; FRegExp := TRegExpr.Create; try setheaders; FHTTPS.HTTPMethod('GET', URL + inttostr(i)); begin FHTML.Clear; FHTML.LoadFromStream(FHTTPS.Document, TEncoding.UTF8); if pos('<steamID64>', FHTML.Text) > 0 then begin FRegExp.Expression := '<steamID64>(.*?)</steamID64>'; if FRegExp.Exec(FHTML.Text) then repeat Synchronize(sync); until not FRegExp.ExecNext; end; end; finally FreeAndNil(FHTTPS); FreeAndNil(FLIST); FreeAndNil(FHTML); FreeAndNil(FRegExp); end; end; procedure TForm1.Button1Click(Sender: TObject); var Threads: integer; begin URL := Edit1.Text + '/memberslistxml/?xml=1&p='; for Threads := 0 to 4 do begin Th[Threads] := Searcher.Create(True); Th[Threads].i := Threads; Th[Threads].FreeOnTerminate := True; Th[Threads].Resume(); end; end; При компиляции ошибка: Код:
[dcc32 Error] Project.pas(98): E2003 Undeclared identifier: 'i' |
#6
|
||||
|
||||
![]() У тебя
Код:
Th: array [0 .. 5] of TThread; jmp $ ; Happy End! The Cake Is A Lie. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
Avenger15 (01.10.2015)
|
#7
|
|||
|
|||
![]() Теперь всё работает!
Спасибо помогавшим! Последний раз редактировалось Avenger15, 01.10.2015 в 16:19. |
#8
|
|||
|
|||
![]() Ещё вопрос:
К примеру , если установить 50 потоков , пройдёт всего 50 страниц. А как сделать так , чтобы 50 потоков работали к примеру с 1000 страниц? То есть установить как-то интервал , к примеру от 100 до 3000. |
#9
|
|||
|
|||
![]() Обычно это делается по другому.
1. Создается очередь (можно TList или TObjectList). 2. Главный поток/приложение "напихивает" в эту очередь задания. 3. Каждый поток смотрит в очередь, если там есть задание, то он его берет себе, а из очереди удаляет. Если ничего нет, то засыпает на некоторое время. 4. Не забываем сделать синхронизацию через CriticlSection при доступе к очереди. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Avenger15 (02.10.2015)
|
#10
|
||||
|
||||
![]() Да, лучше всего сделать, как сказал lmikle.
Если это не понятно - то сделать тупо и нерационально: в каждом потоке сделать цикл от A до B, и передавать при создании не индекс I, а эти границы A и B. jmp $ ; Happy End! The Cake Is A Lie. |
Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
Avenger15 (02.10.2015)
|
#11
|
|||
|
|||
![]() Цитата:
Можно как нибудь в кодовом виде? |
#12
|
|||
|
|||
![]() Да какая идея-то нужна тебе?...
Поток: Код:
type TMyThread = class)TThread) ... public l, h : Integer; // Low and High indices in the Array end; Код:
const NumberOfThreads = 5; ... for i := Low(A) To High(A) Do A[i] := ... // Fill the array // create and run the threads for i := 0 to NumberOfThreads-1 Do begin t := TMyThread.Create(True); t.l := i * Length(A) / NumberOfThreads; t.h := (i+1) * Length(A) / NumberOfThreads - 1; t.resume; end; Но сделать так, как я сказал раньше - правильнее, гибче и эффективнее. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Avenger15 (02.10.2015)
|
#13
|
|||
|
|||
![]() Цитата:
Главная форма Код:
procedure TForm1.Button1Click(Sender: TObject); const NumberOfThreads = 5; var Threads: Integer; A, m: Integer; X: array [3 .. 10] of Integer; begin for m := Low(A) To High(A) Do X[m] := m; URL := Edit1.Text + '/memberslistxml/?xml=1&p='; for Threads := 0 to NumberOfThreads - 1 do begin Th[Threads] := Searcher.Create(True); Th[Threads].i := Threads * Length(A) / NumberOfThreads; Th[Threads].h := (Threads + 1) * Length(A) / NumberOfThreads - 1; Th[Threads].FreeOnTerminate := True; Th[Threads].Start(); end; end; Код:
type Searcher = class(TThread) private FHTTPS: THTTPSend; FLIST, FHTML: TStringList; FRegExp: TRegExpr; protected procedure Execute; override; procedure sync; procedure setheaders; public i, h: Integer; end; |
#14
|
|||
|
|||
![]() Ну, мой код просто написан как пример. Хотя ошибку можно было бы и привести...
По твоему коду. 1. Что за массив такой - Th. Нигде не описан. 2. Зачем вообще оставлять указатели на потоки, если они у тебя FreeOnTerminate и ты к ним потом все-равно не обращаешься? 3. Сорри, вот тут надо округлить или использовать div: Код:
Th[Threads].i := Threads * (Length(A) div NumberOfThreads); Th[Threads].h := (Threads + 1) * (Length(A) div NumberOfThreads) - 1; 5. Вообще, тут тебе и массив-то этот нафиг не нужен, если ты просто передаешь циферки. Т.е., если у тебя интервал 3..10, то Код:
i := 3 + Threads * (10-3) div NumberOfThreads; h := 3 + (Threads + 1) * (Length(A) div NumberOfThreads) - 1; Ну а внутри потока делаешь обычный цикл от i до h. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Avenger15 (04.10.2015)
|