.NET TIPS

ファイル・ダウンロード時の最大同時接続数を変更するには?[C#、VB]

デジタルアドバンテージ 遠藤 孝信
2007/07/19

 WebClientクラスやHttpWebRequest/HttpWebResponseクラス(すべてSystem.Net名前空間)などを使用して*1Webサーバから複数のファイルをダウンロードする際、その処理をマルチスレッド化してもパフォーマンス(スループット)が上がらないことがある。そのような場合には、最大同時接続数の制限が要因となっていることが多い。

*1 これらのクラスの利用方法については「TIPS:WebClientクラスでWebページを取得するには?」「TIPS:WebRequest/WebResponseクラスでWebページを取得するには?」を参照してほしい。

 上述したクラスでダウンロードを行う際の最大同時接続数は、デフォルトで「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サイトに対するアクセスでは、その接続が内部的に再利用される。このプログラムで最初に余分なダウンロードを行っているのは、マルチスレッドによるダウンロードが最初の接続にかかる時間の影響を受けないようにするためだ。End of Article

カテゴリ:クラス・ライブラリ 処理対象:ネットワーク
使用ライブラリ:ServicePointManagerクラス(System.Net名前空間)
使用ライブラリ:WebClientクラス(System.Net名前空間)
関連TIPS:WebClientクラスでWebページを取得するには?
関連TIPS:WebRequest/WebResponseクラスでWebページを取得するには?

この記事と関連性の高い別の.NET TIPS
ファイルのダウンロードをレジューム(再開)するには?
サーバにより指定されたファイル名でファイルをダウンロードして保存するには?
MSDNサブスクリプションで新製品を超高速にダウンロードするには?
[ASP.NET]GridViewコントロールでデータソースの内容を表示するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間