async
andキーワードを使用する場合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 でより適切な選択肢は、HttpClient
classです。上記を使用することにしましたHttpClient
。また、HttpClientHandler
class、特に各リクエストで 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
メソッドを使用してすべてのタスクを待機できます。Task
await
// 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
メソッドを単純に呼び出すことができることに注意してください。Task
WhenAll
// 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
データをできるだけ多く処理することで、さらにパフォーマンスが向上します。