asyncandキーワードを使用する場合await(必須ではありませんが、.NET 4.5 ではこれらを使用すると作業が簡単になります)、まず次のように、キーワードを使用してインスタンスScrapeDataを返すようにメソッドを変更する必要があります。Task<T>async
async Task<DataSet> ScrapeDataAsync(Uri url)
{
// Create the HttpClientHandler which will handle cookies.
var handler = new HttpClientHandler();
// Set cookies on handler.
// Await on an async call to fetch here, convert to a data
// set and return.
var client = new HttpClient(handler);
// Wait for the HttpResponseMessage.
HttpResponseMessage response = await client.GetAsync(url);
// Get the content, await on the string content.
string content = await response.Content.ReadAsStringAsync();
// Process content variable here into a data set and return.
DataSet ds = ...;
// Return the DataSet, it will return Task<DataSet>.
return ds;
}
非同期操作では本質的にWebClientサポートされていないため、おそらくクラスから離れたいと思うことに注意してください。Task<T>.NET 4.5 でより適切な選択肢は、HttpClientclassです。上記を使用することにしましたHttpClient。また、HttpClientHandlerclass、特に各リクエストで Cookie を送信するために使用するCookieContainerプロパティを確認してください。
ただし、これは、キーワードを使用して別の非同期操作 (この場合はページのダウンロードである可能性が高い)awaitを待つ必要があることを意味します。非同期バージョンを使用するには、データをダウンロードする呼び出しを調整する必要があります。await
それが完了したら、通常はそれを呼び出しますが、このシナリオでは変数を呼び出すawaitため、それを行うことはできません。awaitこのシナリオでは、ループを実行しているため、反復ごとに変数がリセットされます。この場合、次のTask<T>ように配列に格納することをお勧めします。
DataSet alldata = ...;
var tasks = new List<Task<DataSet>>();
foreach(var url in the8000urls)
{
// ScrapeData downloads the html from the url with
// WebClient.DownloadString
// and scrapes the data into several datatables which
// it returns as a dataset.
tasks.Add(ScrapeDataAsync(url));
}
にデータをマージする問題がありますallData。そのために、返されたインスタンスでContinueWithメソッドを呼び出し、データを に追加するタスクを実行します。Task<T>allData
DataSet alldata = ...;
var tasks = new List<Task<DataSet>>();
foreach(var url in the8000urls)
{
// ScrapeData downloads the html from the url with
// WebClient.DownloadString
// and scrapes the data into several datatables which
// it returns as a dataset.
tasks.Add(ScrapeDataAsync(url).ContinueWith(t => {
// Lock access to the data set, since this is
// async now.
lock (allData)
{
// Add the data.
}
});
}
次に、クラスのWhenAllメソッドを使用してすべてのタスクを待機できます。Taskawait
// After your loop.
await Task.WhenAll(tasks);
// Process allData
foreachただし、WhenAllがあり、IEnumerable<T>実装が必要であることに注意してください。これは、これが LINQ の使用に適していることを示す良い指標です。
DataSet alldata;
var tasks =
from url in the8000Urls
select ScrapeDataAsync(url).ContinueWith(t => {
// Lock access to the data set, since this is
// async now.
lock (allData)
{
// Add the data.
}
});
await Task.WhenAll(tasks);
// Process allData
必要に応じてクエリ構文を使用しないことも選択できますが、この場合は問題ありません。
含まれているメソッドがとしてマークされていない場合async(コンソール アプリケーションを使用していて、アプリが終了する前に結果を待つ必要があるため)、 を呼び出したときに返されたWaitメソッドを単純に呼び出すことができることに注意してください。TaskWhenAll
// This will block, waiting for all tasks to complete, all
// tasks will run asynchronously and when all are done, then the
// code will continue to execute.
Task.WhenAll(tasks).Wait();
// Process allData.
つまり、ポイントは、Taskインスタンスをシーケンスに収集し、シーケンス全体を待ってから処理することですallData。
ただし、可能であれば、データをマージする前にデータを処理することをallDataお勧めします。データ処理に全体が必要でない限り、 すべてが返されるのを待つのではなく、返されたDataSetデータをできるだけ多く処理することで、さらにパフォーマンスが向上します。