Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 30.09.2015, 22:27
Avenger15 Avenger15 вне форума
Прохожий
 
Регистрация: 17.09.2015
Сообщения: 10
Версия Delphi: Delphi XE3
Репутация: 10
Сообщение Помощь по многопоточности

Прошу у вас помощи.
Суть такова: Создаются 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  
Старый 30.09.2015, 23:02
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,094
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Кажется, вы чего-то не понимаете в потоках. Точнее в их применении.
Фактически, можно говорить о том, что поток - это отдельный процесс. Просто они выполняются в одном адресном пространстве, так что легче организовать взаимодействие между ними. Однако, они остаются все-таки разными процессами. Т.е. если потоку, например, нужно работать с COM, то каждый поток должен инициализировать COM-подсистему.
В вашем конкреном случае я вижу только одну возможность (признаюсь, смотрел не очень внимательно). Вот там, где у вас есть цикл от 1 до 5, каждый поток делает совсем одно и то же. Можно сделать так, что бы каждый поток отрабатывал только одну из цифр (т.е. разные урлы). Тогда каждый поток будет выполнять свою задачу, не пересекаясь по данным c другими. Что будет примерно в 5 раз быстрее (ну не в 5 на самом деле, где-то, ориентировочно, в 3, и то, если сама операция достаточно длительная).
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
Avenger15 (01.10.2015)
  #3  
Старый 30.09.2015, 23:50
Avenger15 Avenger15 вне форума
Прохожий
 
Регистрация: 17.09.2015
Сообщения: 10
Версия Delphi: Delphi XE3
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Кажется, вы чего-то не понимаете в потоках. Точнее в их применении.
Фактически, можно говорить о том, что поток - это отдельный процесс. Просто они выполняются в одном адресном пространстве, так что легче организовать взаимодействие между ними. Однако, они остаются все-таки разными процессами. Т.е. если потоку, например, нужно работать с COM, то каждый поток должен инициализировать COM-подсистему.
В вашем конкреном случае я вижу только одну возможность (признаюсь, смотрел не очень внимательно). Вот там, где у вас есть цикл от 1 до 5, каждый поток делает совсем одно и то же. Можно сделать так, что бы каждый поток отрабатывал только одну из цифр (т.е. разные урлы). Тогда каждый поток будет выполнять свою задачу, не пересекаясь по данным c другими. Что будет примерно в 5 раз быстрее (ну не в 5 на самом деле, где-то, ориентировочно, в 3, и то, если сама операция достаточно длительная).
Цитата:
Сообщение от lmikle
Вот там, где у вас есть цикл от 1 до 5, каждый поток делает совсем одно и то же. Можно сделать так, что бы каждый поток отрабатывал только одну из цифр (т.е. разные урлы). Тогда каждый поток будет выполнять свою задачу, не пересекаясь по данным c другими. Что будет примерно в 5 раз быстрее (ну не в 5 на самом деле, где-то, ориентировочно, в 3, и то, если сама операция достаточно длительная).
Вот это мне и нужно!!! , теперь вопрос как это реализовать в Delphi!

Последний раз редактировалось Avenger15, 01.10.2015 в 00:13.
Ответить с цитированием
  #4  
Старый 01.10.2015, 09:33
icWasya icWasya вне форума
Местный
 
Регистрация: 09.11.2010
Сообщения: 499
Репутация: 10
По умолчанию

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  
Старый 01.10.2015, 10:23
Avenger15 Avenger15 вне форума
Прохожий
 
Регистрация: 17.09.2015
Сообщения: 10
Версия Delphi: Delphi XE3
Репутация: 10
По умолчанию

Цитата:
Сообщение от icWasya
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;
Код:
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  
Старый 01.10.2015, 13:59
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

У тебя
Код:
Th: array [0 .. 5] of TThread;
А ты обращаешься к ним не как к TThread, а как к Searcher.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
Этот пользователь сказал Спасибо Bargest за это полезное сообщение:
Avenger15 (01.10.2015)
  #7  
Старый 01.10.2015, 14:10
Avenger15 Avenger15 вне форума
Прохожий
 
Регистрация: 17.09.2015
Сообщения: 10
Версия Delphi: Delphi XE3
Репутация: 10
По умолчанию

Теперь всё работает!
Спасибо помогавшим!

Последний раз редактировалось Avenger15, 01.10.2015 в 16:19.
Ответить с цитированием
  #8  
Старый 01.10.2015, 16:19
Avenger15 Avenger15 вне форума
Прохожий
 
Регистрация: 17.09.2015
Сообщения: 10
Версия Delphi: Delphi XE3
Репутация: 10
По умолчанию

Ещё вопрос:
К примеру , если установить 50 потоков , пройдёт всего 50 страниц.
А как сделать так , чтобы 50 потоков работали к примеру с 1000 страниц?
То есть установить как-то интервал , к примеру от 100 до 3000.
Ответить с цитированием
  #9  
Старый 01.10.2015, 17:55
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,094
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Обычно это делается по другому.
1. Создается очередь (можно TList или TObjectList).
2. Главный поток/приложение "напихивает" в эту очередь задания.
3. Каждый поток смотрит в очередь, если там есть задание, то он его берет себе, а из очереди удаляет. Если ничего нет, то засыпает на некоторое время.
4. Не забываем сделать синхронизацию через CriticlSection при доступе к очереди.
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
Avenger15 (02.10.2015)
  #10  
Старый 01.10.2015, 18:53
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Да, лучше всего сделать, как сказал lmikle.
Если это не понятно - то сделать тупо и нерационально: в каждом потоке сделать цикл от A до B, и передавать при создании не индекс I, а эти границы A и B.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
Этот пользователь сказал Спасибо Bargest за это полезное сообщение:
Avenger15 (02.10.2015)
  #11  
Старый 01.10.2015, 20:05
Avenger15 Avenger15 вне форума
Прохожий
 
Регистрация: 17.09.2015
Сообщения: 10
Версия Delphi: Delphi XE3
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
сделать тупо и нерационально: в каждом потоке сделать цикл от A до B, и передавать при создании не индекс I, а эти границы A и B.
На самом деле , нет идеи как это реализовать.
Можно как нибудь в кодовом виде?
Ответить с цитированием
  #12  
Старый 01.10.2015, 22:59
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,094
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Да какая идея-то нужна тебе?...
Поток:
Код:
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  
Старый 02.10.2015, 13:31
Avenger15 Avenger15 вне форума
Прохожий
 
Регистрация: 17.09.2015
Сообщения: 10
Версия Delphi: Delphi XE3
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Да какая идея-то нужна тебе?...
Поток:
Код:
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;

Но сделать так, как я сказал раньше - правильнее, гибче и эффективнее.
Вот мой код:
Главная форма
Код:
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  
Старый 02.10.2015, 19:15
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,094
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну, мой код просто написан как пример. Хотя ошибку можно было бы и привести...
По твоему коду.
1. Что за массив такой - Th. Нигде не описан.
2. Зачем вообще оставлять указатели на потоки, если они у тебя FreeOnTerminate и ты к ним потом все-равно не обращаешься?
3. Сорри, вот тут надо округлить или использовать div:
Код:
    Th[Threads].i := Threads * (Length(A) div NumberOfThreads);
    Th[Threads].h := (Threads + 1) * (Length(A) div NumberOfThreads) - 1;
4. Все-равно работать не будет, т.к. этот код предполагает массив с заданиями от 0 до Count-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)
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 20:42.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025