1

TPLSystem.Netクラスとメソッドの両方で十分な経験を積んだ人がいることを本当に願っています

TPL現在の一連のアクションの単純な使用の考えとして始まったものは、私のプロジェクトで停止することになりました。

私はまだ.NETで新鮮なので、TPLを使用して深海にまっすぐジャンプします...

Aspxページのsource/content(html)を使用して抽出しようとしましたWebClient

1日に複数のリクエストがあり(通過するのに約20〜30ページ)、ソースコードから特定の値を抽出します...サーバーがリストにある数少ない毎日のタスクの1つにすぎません。

TPLを使用して実装してみて、速度を上げてみました。

Task.Factory.StartNew()いくつかのWCインスタンスで反復 を試みてみましたが、最初にWCを実行しようとすると、アプリケーションは結果を取得しません。WebClient

これが私の最後の試みです

    static void Main(string[] args)
    {
        EnumForEach<Act>(Execute);
        Task.WaitAll();
    }

    public static void EnumForEach<Mode>(Action<Mode> Exec)
    {
            foreach (Mode mode in Enum.GetValues(typeof(Mode)))
            {
                Mode Curr = mode;

                Task.Factory.StartNew(() => Exec(Curr) );
            }
    }

    string ResultsDirectory = Environment.CurrentDirectory,
        URL = "",
        TempSourceDocExcracted ="",
        ResultFile="";

        enum Act
        {
            dolar, ValidateTimeOut
        }

    void Execute(Act Exc)
    {
        switch (Exc)
        {
            case Act.dolar:
                URL = "http://www.AnyDomainHere.Com";
                ResultFile =ResultsDirectory + "\\TempHtm.htm";
                TempSourceDocExcracted = IeNgn.AgilityPacDocExtraction(URL).GetElementbyId("Dv_Main").InnerHtml;
                File.WriteAllText(ResultFile, TempSourceDocExcracted);
                break;
            case Act.ValidateTimeOut:
                URL = "http://www.AnotherDomainHere.Com";
                ResultFile += "\\TempHtm.htm";
                TempSourceDocExcracted = IeNgn.AgilityPacDocExtraction(URL).GetElementbyId("Dv_Main").InnerHtml;
                File.WriteAllText(ResultFile, TempSourceDocExcracted);
                break;
        }

        //usage of HtmlAgilityPack to extract Values of elements by their attributes/properties
        public HtmlAgilityPack.HtmlDocument AgilityPacDocExtraction(string URL)
        {
            using (WC = new WebClient())
            {
                WC.Proxy = null;
                WC.Encoding = Encoding.GetEncoding("UTF-8");
                tmpExtractedPageValue = WC.DownloadString(URL);
                retAglPacHtmDoc.LoadHtml(tmpExtractedPageValue);
                return retAglPacHtmDoc;
            }
        }

私は何が間違っているのですか?TPLを使用することは可能ですWebClientか、それとも別のツールを使用する必要がありますか(IIS 7 / .net4.5を使用できません)?

4

1 に答える 1

3

少なくともいくつかの問題があります。

  1. 命名 -FlNmは名前ではありません - VisualStudio はスマート コード補完を備えた最新の IDE であり、キーストロークを保存する必要はありません (ここから始めてもかまいません。代替手段もあります。主なことは、一貫性を保つことです: C# コーディング規約.

  2. マルチスレッドを使用している場合は、リソースの共有に注意する必要があります。たとえば、FlNm は静的文字列であり、各スレッド内で割り当てられるため、その値は決定論的ではありません (また、順番に実行されていたとしても、コードは正しく動作しません。各反復でパスにファイル名を追加するため、次のようになります。 c:\TempHtm.htm\TempHtm.htm\TempHtm.htm のように)

  3. あなたは異なるスレッドから同じファイルに書き込んでいます (まあ、少なくともそれがあなたの意図だったと思います) - 通常、これはマルチスレッドでの災害のレシピです。質問は、ディスクに何かを書き込む必要があるか、または文字列としてダウンロードしてディスクに触れずに解析できるかどうかです-ディスクに触れるとはどういう意味かの良い例があります。

  4. 全体として、ダウンロードのみを並列化する必要があると思います。そのため、HtmlAgilityPack をマルチスレッドに関与させないでください。それがスレッドセーフであることを知らないと思います。一方、ダウンロードのパフォーマンス/スレッド カウントの比率、html 解析は良好です。スレッド カウントがコア カウントと等しい場合はそうではありませんが、それ以上ではない可能性があります。さらに、テスト、理解、および保守が容易になるため、ダウンロードと解析を分離します。

更新: 私はあなたの完全な意図を理解していませんが、これはあなたが始めるのに役立つかもしれません (これは製品コードではありません。再試行/エラーキャッチなどを追加する必要があります)。また、最後に拡張された WebClient クラスがあり、デフォルトで webclient は 2 つの接続しか許可しないため、より多くのスレッドを回転させることができます。

class Program
{
    static void Main(string[] args)
    {
        var urlList = new List<string>
                          {
                              "http://google.com",
                              "http://yahoo.com",
                              "http://bing.com",
                              "http://ask.com"
                          };

        var htmlDictionary = new ConcurrentDictionary<string, string>();
        Parallel.ForEach(urlList, new ParallelOptions { MaxDegreeOfParallelism = 20 }, url => Download(url, htmlDictionary));
        foreach (var pair in htmlDictionary)
        {
            Process(pair);
        }
    }

    private static void Process(KeyValuePair<string, string> pair)
    {
        // do the html processing
    }

    private static void Download(string url, ConcurrentDictionary<string, string> htmlDictionary)
    {
        using (var webClient = new SmartWebClient())
        {
            htmlDictionary.TryAdd(url, webClient.DownloadString(url));
        }
    }
}

public class SmartWebClient : WebClient
{
    private readonly int maxConcurentConnectionCount;

    public SmartWebClient(int maxConcurentConnectionCount = 20)
    {
        this.maxConcurentConnectionCount = maxConcurentConnectionCount;
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        var httpWebRequest = (HttpWebRequest)base.GetWebRequest(address);
        if (httpWebRequest == null)
        {
            return null;
        }

        if (maxConcurentConnectionCount != 0)
        {
            httpWebRequest.ServicePoint.ConnectionLimit = maxConcurentConnectionCount;
        }

        return httpWebRequest;
    }
}
于 2012-11-22T14:40:39.377 に答える