Where
PLINQを使用してフィルタリング(擬似コード)する方がよいでしょう。
var results = from i in input.AsParallel()
let u = get the URL from i
let d = get the data from u
let v = try get the value from d
where v is found
select new {
Url = u,
Value = v
};
その下にAsParallel
は、TPLのLINQ演算子(Select
、、Where
...)の実装が使用されます。
更新:より多くの情報があります
まず、コードにはいくつかの問題があります。
変数htmlcon
はstatic
、複数のスレッドによって直接使用されます。これが根本的な問題である可能性があります。2つの入力値だけを考えてください。最初のスレッドはGet
設定を完了します。その後、2番目のスレッドを開始するためhtmlcon
のスレッドの呼び出しはHTML GETを完了し、に書き込みます。`メールでcopyMails
Get
htmlcon
このリストemailList
には、複数のスレッドによってロックされることなくアクセスすることもできます。.NET(およびその他のプログラミングプラットフォーム)のほとんどのコレクションタイプはスレッドセーフではないため、一度に1つのスレッドへのアクセスを制限する必要があります。
それぞれの方法でさまざまな活動を混同しています。単一責任の原則を適用することを検討してください。
Thread.Sleep
例外を処理するには?!例外を処理できない(つまり、条件を解決できない)場合は、何もしません。この場合、アクションがスローされると、Parallel.Foreach
willがスローされます。これは、HTMLGETの失敗を処理する方法を定義するまで実行されます。
3つの提案:
私の経験では、クリーンなコード(執拗な程度まで)は物事を簡単にします:フォーマットの詳細は重要ではありません(1つの真のブレーススタイルが優れていますが、一貫性が重要です)。フォーマットを確認してクリーンアップするだけで、問題#1と#2が発生しました。
良いネーミング。ドメインの重要な用語でない限り、数行を超えるコードで使用されているものを省略しないでください。例えば。s
並列ループのアクションパラメータは実際にはURLなので、それを呼び出します。この種のことは、コードをすぐに理解しやすくします。
電子メールの正規表現について考えてみてください。一致しない有効な電子メールが多数あります(たとえば+
、複数の論理アドレスを提供するための使用:ローカルルールexmaple+one@gamil.com
に配信さexample@gmail.com
れ、ローカルルールに使用できます)。また、アポストロフィ( " '
")は有効な文字です(そして、これを間違えてアドレスを拒否したWebサイトに不満を感じている既知の人々)。
2番目:比較的直接的なクリーンアップ:
public static string Get(string url, bool proxy) {
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
if (proxy) {
req.Proxy = new WebProxy(proxyIP + ":" + proxyPort);
}
req.Method = "GET";
req.UserAgent = Settings1.Default.UserAgent;
if (Settings1.Default.EnableCookies == true) {
CookieContainer cont = new CookieContainer();
req.CookieContainer = cont;
}
using (WebResponse resp = req.GetResponse())
using (StreamReader SR = new StreamReader(resp.GetResponseStream())) {
return SR.ReadToEnd();
}
}
private static Regex emailMatcher = new Regex(@"(\b[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b)", RegexOptions.Singleline);
private static string[] ExtractEmails(string htmlContent) {
return emailMatcher.Matches(htmlContent).OfType<Match>
.Select(m => m.Groups[1].Value)
.Distinct()
.ToArray();
}
private void SEbgWorker_DoWork(object sender, DoWorkEventArgs e) {
Parallel.ForEach(allSElist.OfType<string>(), url => {
var htmlContent = Get(url, Settings1.Default.Proxyset);
var emails = ExtractEmails(htmlContent);
foreach (var email in emails) {
Action dgeins = () => mailDataGrid.Rows.Insert(0, email, url);
mailDataGrid.BeginInvoke(dgeins);
}
}
ここに私が持っています:
- ステートメントを利用し
using
て、リソースのクリーンアップを自動化しました。
- すべての変更可能な共有状態を排除しました。
Regex
スレッドセーフなインスタンスメソッドを持つように明示的に文書化されています。したがって、必要なインスタンスは1つだけです。
- ノイズの除去:
ExtractEmails
抽出ではURLが使用されないため、URLを渡す必要はありません。
Get
HTML取得のみを実行しExtreactEMail
、抽出のみを実行するようになりました
3番目:上記は、最も遅い操作であるHTMLGETでスレッドをブロックします。
HttpWebRequest.GetResponse
本当の並行性の利点は、応答ストリームをそれらの非同期の同等のものに置き換えて読み取ることです。
.NET 4では使用Task
することが答えになりますが、/メソッドのペアが提供されていないため、Stream
自分で直接操作してエンコードする必要があります。しかし、.NET 4.5はほぼここにあるので、いくつかを適用します/ :StreamReader
BeginABC
EndABC
async
await
- で何もしません
ExtractEMails
。
Get
は非同期になり、HTTPGETでブロックすることも結果を読み取ることもできません。
SEbgWorker_DoWork
タスクを直接使用して、TPLを操作するためのさまざまな方法が混ざりすぎないようにします。は単純に続行できるので(失敗していない場合–特に指定しない限り、前のタスクが正常に完了した場合にのみ続行します)Get
:Task<string>
ContinueWith
これは.NET4.5で機能するはずですが、これが機能する有効なURLのセットがないと、テストできません。
public static async Task<string> Get(string url, bool proxy) {
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
if (proxy) {
req.Proxy = new WebProxy(proxyIP + ":" + proxyPort);
}
req.Method = "GET";
req.UserAgent = Settings1.Default.UserAgent;
if (Settings1.Default.EnableCookies == true) {
CookieContainer cont = new CookieContainer();
req.CookieContainer = cont;
}
using (WebResponse resp = await req.GetResponseAsync())
using (StreamReader SR = new StreamReader(resp.GetResponseStream())) {
return await SR.ReadToEndAsync();
}
}
private static Regex emailMatcher = new Regex(@"(\b[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b)", RegexOptions.Singleline);
private static string[] ExtractEmails(string htmlContent) {
return emailMatcher.Matches(htmlContent).OfType<Match>
.Select(m => m.Groups[1].Value)
.Distinct()
.ToArray();
}
private void SEbgWorker_DoWork(object sender, DoWorkEventArgs e) {
tasks = allSElist.OfType<string>()
.Select(url => {
return Get(url, Settings1.Default.Proxyset)
.ContinueWith(htmlContentTask => {
// No TaskContinuationOptions, so know always OK here
var htmlContent = htmlContentTask.Result;
var emails = ExtractEmails(htmlContent);
foreach (var email in emails) {
// No InvokeAsync on WinForms, so do this the old way.
Action dgeins = () => mailDataGrid.Rows.Insert(0, email, url);
mailDataGrid.BeginInvoke(dgeins);
}
});
});
tasks.WaitAll();
}