|
.NET TIPS
ファイル・ダウンロード時の最大同時接続数を変更するには?[C#、VB]
デジタルアドバンテージ 遠藤 孝信
2007/07/19 |
|
|
WebClientクラスやHttpWebRequest/HttpWebResponseクラス(すべてSystem.Net名前空間)などを使用して*1Webサーバから複数のファイルをダウンロードする際、その処理をマルチスレッド化してもパフォーマンス(スループット)が上がらないことがある。そのような場合には、最大同時接続数の制限が要因となっていることが多い。
上述したクラスでダウンロードを行う際の最大同時接続数は、デフォルトで「2」である。つまり、いくらダウンロードを行うスレッドを増やしても、同時には2つのファイルしかダウンロードできないということだ(ほかのスレッドはそのダウンロードの完了を待たなければならない)。
ServicePointManagerクラスのDefaultConnectionLimitプロパティ
ダウンロード時の最大同時接続数を変更するには、
System.Net.ServicePointManager.DefaultConnectionLimit
の値を変更すればよい(このDefaultConnectionLimitプロパティは静的プロパティあり、その既定値は「2」)。
ここで、ServicePointManagerクラスはServicePointクラスのオブジェクトを管理するクラスであり(ともにSystem.Net名前空間のクラス)、ServicePointクラスはWebサイトとの接続(HTTP接続)を管理する大本のクラスである*2。
*2 内部的には、WebClientクラスはHttpWebRequest/HttpWebResponseクラスを利用し、HttpWebRequest/HttpWebResponseクラスはServicePointクラスを利用してWebへのアクセスを行っている。ちなみにServicePointクラスはソケット(Socketクラス)によりWebサイトに接続する。
|
複数スレッドで同時にダウンロードを行うサンプル・プログラム
次のプログラムは、Insider.NETの過去記事一覧ページ(サイズは約500Kbytes)を10個のスレッドでそれぞれ同時にダウンロードするサンプル・プログラムだ。
// maxconnum.cs
using System;
using System.Net;
using System.Threading;
class MaxConnection {
// 過去記事一覧ページのダウンロード
static void download(int i) {
string atmarkit = "http://www.atmarkit.co.jp/fdotnet/index/all/old.html";
WebClient wc = new WebClient();
wc.DownloadString(atmarkit);
Console.WriteLine("ダウンロード完了:{0}", i);
}
// 別スレッドで実行されるメソッド
static void worker(object i) {
download((int)i);
}
static void Main() {
// 最大同時接続数
ServicePointManager.DefaultConnectionLimit = 2; // デフォルト
Thread[] t = new Thread[10];
Console.WriteLine("-- 事前ダウンロード開始 --");
download(-1);
// 出力:ダウンロード完了:-1
Console.WriteLine("-- 一斉ダウンロード開始 --");
for (int i = 0; i < 10; i++) {
t[i] = new Thread(worker);
t[i].Start(i); // workerメソッドの実行
}
// 出力例:
// ダウンロード完了:0
// ダウンロード完了:1
// ダウンロード完了:4
// ダウンロード完了:6
// ダウンロード完了:9
// ダウンロード完了:8
// ダウンロード完了:3
// ダウンロード完了:5
// ダウンロード完了:7
// ダウンロード完了:2
}
}
// コンパイル方法:csc maxconnum.cs
|
|
複数スレッドで同時にダウンロードを行うC#のサンプル・プログラム(maxconnum.cs) |
|
' maxconnum.vb
Imports System
Imports System.Net
Imports System.Threading
Class MaxConnection
' 過去記事一覧ページのダウンロード
Shared Sub download(ByVal i As Integer)
Dim url As String = "http://www.atmarkit.co.jp/fdotnet/index/all/old.html"
Dim wc As New WebClient()
wc.DownloadString(url)
Console.WriteLine("ダウンロード完了:{0}", i)
End Sub
' 別スレッドで実行されるメソッド
Shared Sub worker(ByVal i As Object)
download(CType(i, Integer))
End Sub
Shared Sub main()
' 最大同時接続数
ServicePointManager.DefaultConnectionLimit = 2 ' デフォルト
Dim t(9) As Thread
Console.WriteLine("-- 事前ダウンロード開始 --")
download(-1)
' 出力:ダウンロード完了:-1
Console.WriteLine("-- 一斉ダウンロード開始 --")
For i As Integer = 0 To 9
t(i) = New Thread(AddressOf worker)
t(i).Start(i)
Next
' 出力例:
' ダウンロード完了:0
' ダウンロード完了:1
' ダウンロード完了:4
' ダウンロード完了:6
' ダウンロード完了:9
' ダウンロード完了:8
' ダウンロード完了:3
' ダウンロード完了:5
' ダウンロード完了:7
' ダウンロード完了:2
End Sub
End Class
' コンパイル方法:vbc maxconnum.vb
|
|
複数スレッドで同時にダウンロードを行うVBのサンプル・プログラム(maxconnum.vb) |
|
筆者のPCでこのサンプル・プログラムを実行した場合、「DefaultConnectionLimit = 2」のままでは「ダウンロード完了:X」のメッセージがさみだれ式に表示されたのに対して、これを例えば「10」に変更すれば10個のメッセージはほぼ同時に表示され*3、すべてのダウンロードの完了にかかる総時間が大幅に短縮された(ただし、サーバ側の負荷状況やPCのプロキシ設定などで挙動は変化する)。
*3 HTTP/1.1の仕様では、「1つのサーバに対する同時接続数は2以下にすべき」とされている(詳細は「RFC 2616(英文)」を参照)ため、実際には、このような設定は社内サーバなどでの利用にのみとどめるべきである。
|
なお、同一Webサイトに対するアクセスでは、その接続が内部的に再利用される。このプログラムで最初に余分なダウンロードを行っているのは、マルチスレッドによるダウンロードが最初の接続にかかる時間の影響を受けないようにするためだ。
|
generated by
|
|
Insider.NET 記事ランキング
本日
月間