흥미로운 데이터가있는 페이지가 많이있는 웹 사이트를 긁어 내고 싶지만 소스가 매우 크기 때문에 다중 스레드를 사용하여 과부하를 제한하려고합니다. Parallel.ForEach
을 사용하여 10 개의 작업으로 구성된 각 청크를 시작하고 활성 스레드 수가 임계 값 아래로 떨어질 때까지 기본 for
루프를 기다립니다. 이를 위해 WebClient
이라는 새 스레드를 시작할 때 활성 스레드의 카운터를 사용하고 WebClient
의 DownloadStringCompleted
이벤트가 트리거 될 때 감소합니다.웹 사이트의 여러 페이지를 다듬기위한 병렬 요청
원래 질문은 DownloadString
대신 DownloadStringTaskAsync
을 사용하고 Parallel.ForEach
에서 시작된 각 스레드가 완료 될 때까지 기다리는 것이 좋습니다. 이 문제는 해결 방법으로 해결되었습니다. 카운터가 (activeThreads
)이고 기본 foor 루프에 Thread.Sleep
이 있습니다.
DownloadString 데이터가 도착할 때까지 기다리는 동안 스레드를 해제하여 DownloadString
대신 모든 속도를 향상 시키려면 await DownloadStringTaskAsync
을 사용하고 있습니까?
원래의 질문으로 돌아가려면 TPL을 사용하여 카운터를 포함시키지 않고보다 우아하게이 방법을 사용할 수 있습니까?
private static volatile int activeThreads = 0;
public static void RecordData()
{
var nbThreads = 10;
var source = db.ListOfUrls; // Thousands urls
var iterations = source.Length/groupSize;
for (int i = 0; i < iterations; i++)
{
var subList = source.Skip(groupSize* i).Take(groupSize);
Parallel.ForEach(subList, (item) => RecordUri(item));
//I want to wait here until process further data to avoid overload
while (activeThreads > 30) Thread.Sleep(100);
}
}
private static async Task RecordUri(Uri uri)
{
using (WebClient wc = new WebClient())
{
Interlocked.Increment(ref activeThreads);
wc.DownloadStringCompleted += (sender, e) => Interlocked.Decrement(ref iterationsCount);
var jsonData = "";
RootObject root;
jsonData = await wc.DownloadStringTaskAsync(uri);
var root = JsonConvert.DeserializeObject<RootObject>(jsonData);
RecordData(root)
}
}
추가 연장없이 무언가를 갖고 싶었지만 이것은 흥미 롭습니다. 왜 그런지는 잘 모르지만 그대로있는 것은 아닙니다. 그것은 나에게 비어있는 json을 준다 – sofsntp
@sofsntp - 테스트했을 때 잘 돌아갔다. subscribe 메소드에서 JSON이 아니라 URI가 있는지 확인 했습니까? 구독을 할 때까지 JSON을 deserialize하지 않도록 코드를 변경하십시오. – Enigmativity
그래 그래도 작동하지만이 일의 요점은 무엇입니까? 무엇이 그것을 우아하게 하는가? – sofsntp