|   | 
 
|  
 .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 記事ランキング
		
		
			本日
			月間