![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | 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; |
| Этот пользователь сказал Спасибо 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. |
| Этот пользователь сказал Спасибо 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)
| ||