2011-11-06 3 views
0

웹 페이지 소스를 메모 구성 요소로 가장 빨리 다운로드하는 방법은 무엇입니까? Indy 및 HttpCli 구성 요소를 사용합니다.빨리 다운로드하는 방법?

문제는 내가 100 개가 넘는 사이트로 채워진 목록 상자가 있는데, 내 프로그램은 소스를 메모로 다운로드하고 mp3 파일의 소스를 구문 분석합니다. 그것은 Google 음악 검색 프로그램과 같은 것입니다. Google 검색을 사용하여 Google 검색을 쉽게합니다.

내 질문에 이르는 스레드에 대한 읽기 시작 : IdHttp 인스턴스를 구문 분석 함수가있는 스레드에서 만들고 목록 상자에서 사이트의 절반을 구문 분석하도록 말할 수 있습니까?

그래서 기본적으로 사용자가 클릭 구문 분석 할 때, 메인 스레드가 수행해야합니다

for i := 0 to listbox1.items.count div 2 do 
    get and parse 
, 다른 스레드가 수행해야합니다

for i := form1.listbox1.items.count div 2 to form1.listbox1.items.count - 1 do 
    get and parse. 

을, 그래서 그들은에서 form1.listbox2에 구문 분석 된 내용을 추가 할 것 동시. 또는 주 스레드에서 두 개의 IdHttp 인스턴스를 시작하는 것이 더 쉬울 수도 있습니다. 하나는 사이트의 첫 번째 절반을위한 것이고 다른 하나는 두 번째를위한 것입니까?

이를 위해 : Indy 또는 Synapse를 사용해야합니까?

+0

난 당신이 동기화가하는 일에 대한 문서를 읽어 제안, 그리고 그것을 시작 후 때마다 하나 개의 URL을 처리 할 때 각 스레드가 단 하나의 URL을 요청 할 것입니다. 웹 사이트에서 XHTML을 사용하는 경우 MSXML2_TLB의 DOMDocument.load 메서드를 검사하여로드 및 구문 분석이 제대로 수행되는지 확인합니다. –

답변

9

단일 URL을 읽고 해당 내용을 처리 할 수있는 스레드를 만듭니다. 그런 다음 동시에 얼마나 많은 스레드를 실행할지 결정할 수 있습니다. 귀하의 컴퓨터는 꽤 많은 연결을 허용 할 것입니다. 따라서 100 개의 사이트가 다른 호스트 이름을 가지고 있다면, 동시에 10 개 또는 20 개를 실행하는 것이 문제가되지 않습니다. 과도 함은 너무 많지만 프로세서 시간 낭비가 너무 적습니다.

다운로드 및 처리를위한 별도의 스레드를 사용하여이 프로세스를 더욱 조정할 수 있으므로 지속적으로 많은 스레드가 콘텐츠를 다운로드 할 수 있습니다. 다운로드는 프로세서 집약적이지 않습니다. 기본적으로 응답을 기다리고 있기 때문에 비교적 많은 수의 다운로드 스레드를 쉽게 가질 수 있으며 다른 작업자 스레드 몇 개는 결과 풀에서 항목을 가져 와서 처리 할 수 ​​있습니다.
그러나 다운로드 및 처리를 분할하면 조금 더 복잡해지며 아직 그 도전에 부딪치지 않는다고 생각합니다.

현재 다른 문제가 있기 때문에 처음에는 스레드에서 VCL 구성 요소를 사용하지 않습니다. 스레드의 목록 상자에서 정보가 필요한 경우 스레드에서 동기화를 사용하여 주 스레드에 '안전한'호출을해야하거나 스레드를 시작하기 전에 필요한 정보를 전달해야합니다. 후자는 더 효율적입니다. 왜냐하면 Synchronize를 사용하여 실행 된 코드가 실제로 주 스레드에서 실행되기 때문에 멀티 스레딩이 덜 효율적이기 때문입니다.

하지만 실제로는 첫 번째 줄에 "웹 페이지 소스를 메모 구성 요소로 다운로드"으로 그려졌습니다. 그렇게하지 마! 처리를 위해 메모에 결과를로드하지 마십시오. 자동 처리는 시각적 컨트롤 외부의 메모리에서 수행하는 것이 가장 좋습니다. 텍스트를 처리하기 위해 문자열, 스트림 또는 문자열 목록을 사용하는 것이 메모를 사용하는 것보다 훨씬 빠릅니다.
stringlist도 약간의 오버 헤드를 가지고 있지만, 라인을 인덱싱하는 동일한 구조 (메모의 Lines 속성 인 TMemoStrings 및 TStringList는 모두 동일한 조상을 가짐)를 사용하므로이 기능을 사용하는 코드가 있다면 TStringList로 변환하는 것은 아주 쉽습니다.

+2

Downvoter, 당신이 틀렸다고 생각하는 동기를 부여 할 수 있습니까? – GolezTrol

+0

+1 좋은 접근 방식과 메모 컨트롤을 사용하는 것이 나쁜 생각임을 지적 해 주셔서 감사합니다. 매우 유용한 스레드 안전 문자열 목록을 발견했습니다. Tilo Eckert의 TThreadStringList : http://www.swissdelphicenter.ch/torry/showcode.php?id=2167 TStringList를 둘러싼 래퍼입니다. 중요한 섹션을 사용하여 기본 문자열 목록에 안전하게 액세스 할 수 있습니다. –

+0

다운로드 할 항목 목록에 TThreadStringList를 사용하는 것이 실제로 편리합니다. 다운로드 된 각 항목은 처리를 위해 별도의 TThreadStringList에 푸시 될 수 있습니다. 그런 식으로, 당신은 너무 많은 번거 로움없이, 내가 제안한 것처럼 다운로드와 처리를 나눌 수있다. – GolezTrol

5

나는 모든 파싱을 스레드에서 수행하고, 메인 스레드는 파싱을 전혀하지 말 것을 제안합니다. 주 스레드는 UI 만 관리해야합니다. TMemo에서 HTML을 구문 분석하지 말고 각 스레드가 TStream 또는 String으로 다운로드 한 다음 직접 파싱하십시오. TIdSync 또는 TIdNotify를 사용하여 구문 분석 결과를 UI에 보내 표시 할 수 있습니다 (속도가 중요 할 경우 TIdNotify 사용). 구문 분석 논리에 UI 구성 요소를 포함 시키면 속도가 느려집니다.

+1

파서가 구문 분석 만하는 것이 아니라 일부 데이터 처리를 수행하는 경우 파서가 100 % 다중 스레드 안전하지 않을 수 있습니다. IMHO 구문 분석은 다운로드하는 것보다 훨씬 빠릅니다. –

+0

목록 상자에서 % 20, % 3D 등을 바꾸려면 그냥 다운로드하고 구문 분석하고 stringreplace ... –

+0

최종 결과를 표시 할 준비가 될 때까지 UI를 사용하지 않고이 모든 작업을 수행 할 수 있습니다. URL을 TStringList로 모으고 각 스레드가 String 또는 TMemoryStream (TIdHTTP 모두를 지원함)로 다운로드하고 데이터를 구문 분석 한 후 TIdNotify를 사용하여 결과를 메인 스레드에 게시하는 목록 항목에 필요한 스레드를 생성합니다. 이는 스레드로부터 안전하며 불필요한 UI 병목 현상을 방지합니다. –

4

인디 또는 시냅스는 모두 다중 스레드를 지원합니다. Indy보다 훨씬 가볍고 Synpase를 사용하는 것이 좋을 것입니다. Microsoft가 제공 한 HTTP APIs을 잊지 마십시오.

간단한 구현 : URI 당

  • 하나의 스레드;
  • 각 스레드는 하나의 HTTP 통신을 사용하여 데이터를 가져옵니다.
  • 그런 다음 각 스레드가 데이터를 구문 분석합니다.
  • 그런 다음 Synchronize을 사용하여 UI를 새로 고칩니다.

아마 내가 제일 좋아하는 :

  • 최대 스레드 수를 정의를 사용합니다 (예를 들어, 8);
  • 이 스레드들 각각은 원격 연결을 유지합니다 (이것은 HTTP/1.1의 목적이며 실제로 속도를 변화시킬 수 있습니다).
  • 모든 요청은 그 스레드에 의해 검색됩니다 하나 하나 - 스레드에 URL을 할당 할 사전하지만, 쓰레드가 하나 완료되면 (각 URL은 항상 같은 시간을 고려하지 않음) 글로벌 목록에서 새 URL을 검색하지 않는다; 다른 URI 때까지 대기 할 수있다
  • 스레드는 전역 목록 (예를 들어 Sleep(100) 또는 세마포어를 사용하여)에 첨가;
  • 그런 다음 전용 GUI 메시지 (WM_USER+...)를 사용하여 기본 GUI 스레드의 UI를 구문 분석하고 업데이트하십시오. 구문 분석은 빠른 IMHO가 될 것입니다 (UI 새로 고침이 느려질 수 있음을 기억하십시오) - 예를 들어 BeginUpdate-EndUpdate 메서드를 봅니다. GDI 메시지 (관련 HTML 데이터 포함)가 배경 스레드를 차단하는 Synchronize을 사용하는 것보다 효율적이라는 것을 알았습니다.
  • 또 다른 옵션은 그 URI에서 데이터를 검색 한 후, 백그라운드 스레드에서 구문 분석을하는 것입니다 - (당신의 파서가 느린 경우에만)를 아마도 가치가 없어, 당신 파서 경우 멀티 스레딩 문제로 올 수 있습니다/데이터 프로세서는 100 % 스레드로부터 안전하지 않습니다.

제 2는 소위 "다운로드 관리자는"어떻게 구현되는지 인기가있다.

당신이 멀티 스레딩을 처리 할 때, 당신은 당신의 공유 자원 (목록, 예를 들어)를 "보호"해야합니다. TCriticalSection을 사용하여 모든 목록 (예 : URI 목록)에 액세스하고 최대한 빨리 잠금을 해제하십시오.

여러 컴퓨터와 네트워크, 동시 액세스, 다양한 운영 체제로 구현을 테스트 해보십시오. 멀티 스레드 응용 프로그램을 디버깅하는 것은 어려울 수 있습니다. 따라서 구현이 간단해질수록 더 좋습니다. 다운로드 부분을 멀티 스레드로 만들 것을 권장하지만, 메인 스레드가 데이터를 처리하게하십시오. 빠르다).

+0

나에게 간단한 코드를 제공하여 목록에서 URL을 검색하는 방법을 제공 할 수 있습니다. 왜냐하면 listbox에서 100 개의 URL을 8 개의 스레드로 분할하는 방법을 모르기 때문에 변수 링크를 만들고 thread.resume보다 먼저 어떻게 보내겠습니까? 덕분에 링크를주었습니다. 감사합니다. –

+1

@DanijelMaksimovicMaxa URI는 단지 새로운 TStringList입니다.이 파일은 새로운 파일을 다운로드 할 때 모든 스레드에서 읽을 수 있습니다. 스레드에 URI를 할당하지는 않지만 다운로드 할 남아있는 URI에 대해 스레드가 목록에 요청하게합니다. 한 번에 같은 URI를 검색하는 두 개의 스레드를 피하기 위해 TCriticalSection을 사용하여 목록에 대한 액세스를 보호해야합니다. –

관련 문제