私はチェックがプロキシはプロキシを使用してHTTPリクエストを送信することにより、作業している場合は、そのJavaでソフトウェアの一部を書かれています。
それは、彼らが動作しているかどうかを確認しようと、データベースから周り3万プロキシをとります。使用されるデータベースから受信したプロキシは、として返されるArrayList<String>
が、それに変更されているDeque<String>
下記の理由のために。
プログラムの仕組みがありますあるProxyRequest
オブジェクトは、それぞれの文字列とintとして保存IP&ポートという。ProxyRequest
オブジェクトは、メソッド有しisWorkingProxy()
試みがプロキシを使用して要求を送信すると返しboolean
、それが成功したかどうか。
このProxyRequest
オブジェクトはで巻き付けられているRunnableProxyRequest
オブジェクトの呼び出しそのsuper.isWorkingProxy()
オーバーライドでrun()
の方法。以下からの応答に基づいてsuper.isWorkingProxy()
、RunnableProxyRequest
オブジェクトは、MySQLデータベースを更新します。
MySQLデータベースの更新があることをメモしていますsynchronized()
。
これは、(VPS上)FixedThreadPoolを使用して750件のスレッド上で実行されますが、終わりに向かって、それは明らかにガベージコレクタが動作している暗示され、非常に遅い(〜50件のスレッドのスタック)になります。これが問題です。
私はそれが動作するようには思えない、遅れを改善するために、次のことを試みました。
1)使用したDeque<String>
プロキシを使用し、Deque.pop()
取得するためにString
プロキシがあるです。これは、(私は信じて)、連続して作るDeque<String>
GCによって引き起こされる遅れを改善すべき、小さくします。
2)を設定しcon.setConnectTimeout(this.timeout);
た場合、this.timeout = 5000;
この方法では、接続は5秒で結果を返す必要があります。ない場合は、スレッドが終了し、もはや、スレッドプールでアクティブにはなりません。
このほかに、私はパフォーマンスを向上させることができ、他の方法を知りません。
誰も私がGCによってスレッドの終わりに向かって遅れ回避/停止にパフォーマンスを向上させるための方法をお勧めしますか?私はこれについてStackOverflowの質問(あることがわかっているJavaスレッドは処理の終わりに向かって遅くなるが)、私は答えにすべてを試してみましたが、それが私のために働いていません。
お時間をいただき、ありがとうございます。
コードスニペット:
ループにスレッドを追加しますFixedThreadPool
:
//This code is executed recursively (at the end, main(args) is called again)
//Create the threadpool for requests
//Threads is an argument that is set to 750.
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(threads);
Deque<String> proxies = DB.getProxiesToCheck();
while(proxies.isEmpty() == false) {
try {
String[] split = proxies.pop().split(":");
Runnable[] checks = new Runnable[] {
//HTTP check
new RunnableProxyRequest(split[0], split[1], Proxy.Type.HTTP, false),
//SSL check
new RunnableProxyRequest(split[0], split[1], Proxy.Type.HTTP, true),
//SOCKS check
new RunnableProxyRequest(split[0], split[1], Proxy.Type.SOCKS, false)
//Add more checks to this list as time goes...
};
for(Runnable check : checks) {
executor.submit(check);
}
} catch(IndexOutOfBoundsException e) {
continue;
}
}
ProxyRequest
クラス:
//Proxy details
private String proxyIp;
private int proxyPort;
private Proxy.Type testingType;
//Request details
private boolean useSsl;
public ProxyRequest(String proxyIp, String proxyPort, Proxy.Type testingType, boolean useSsl) {
this.proxyIp = proxyIp;
try {
this.proxyPort = Integer.parseInt(proxyPort);
} catch(NumberFormatException e) {
this.proxyPort = -1;
}
this.testingType = testingType;
this.useSsl = useSsl;
}
public boolean isWorkingProxy() {
//Case of an invalid proxy
if(proxyPort == -1) {
return false;
}
HttpURLConnection con = null;
//Perform checks on URL
//IF any exception occurs here, the proxy is obviously bad.
try {
URL url = new URL(this.getTestingUrl());
//Create proxy
Proxy p = new Proxy(this.testingType, new InetSocketAddress(this.proxyIp, this.proxyPort));
//No redirect
HttpURLConnection.setFollowRedirects(false);
//Open connection with proxy
con = (HttpURLConnection)url.openConnection(p);
//Set the request method
con.setRequestMethod("GET");
//Set max timeout for a request.
con.setConnectTimeout(this.timeout);
} catch(MalformedURLException e) {
System.out.println("The testing URL is bad. Please fix this.");
return false;
} catch(Exception e) {
return false;
}
try(
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
) {
String inputLine = null; StringBuilder response = new StringBuilder();
while((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
//A valid proxy!
return con.getResponseCode() > 0;
} catch(Exception e) {
return false;
}
}
RunnableProxyRequest
クラス:
public class RunnableProxyRequest extends ProxyRequest implements Runnable {
public RunnableProxyRequest(String proxyIp, String proxyPort, Proxy.Type testingType, boolean useSsl) {
super(proxyIp, proxyPort, testingType, useSsl);
}
@Override
public void run() {
String test = super.getTest();
if(super.isWorkingProxy()) {
System.out.println("-- Working proxy: " + super.getProxy() + " | Test: " + test);
this.updateDB(true, test);
} else {
System.out.println("-- Not working: " + super.getProxy() + " | Test: " + test);
this.updateDB(false, test);
}
}
private void updateDB(boolean success, String testingType) {
switch(testingType) {
case "SSL":
DB.updateSsl(super.getProxyIp(), super.getProxyPort(), success);
break;
case "HTTP":
DB.updateHttp(super.getProxyIp(), super.getProxyPort(), success);
break;
case "SOCKS":
DB.updateSocks(super.getProxyIp(), super.getProxyPort(), success);
break;
default:
break;
}
}
}
DB
クラス:
//Locker for async
private static Object locker = new Object();
private static void executeUpdateQuery(String query, String proxy, int port, boolean toSet) {
synchronized(locker) {
//Some prepared statements here.
}
}
おかげでピーターLawreyソリューションに私を導くための!:)
彼のコメント:
@ILoveKali私は物事が本当に間違って行くときのネットワークライブラリが接続をシャットダウンするには積極的に十分ではありません発見しました。タイムアウトは、接続が細かいときに最適に動作する傾向があります。YMMV
私はいくつかの研究を行ったので、私はまた、メソッドを使用していたことがわかりましたsetReadTimeout(this.timeout);
。以前、私は使用していましたsetConnectTimeout(this.timeout);
!
この投稿への感謝(HttpURLConnectionのタイムアウトのデフォルト値以下に説明):
残念ながら、私の経験では、サーバーへの接続に何が起こるかに応じて、不安定な状態になることができ、これらのデフォルトを使用して表示されます。あなたは(少なくとも読み取り)タイムアウトをHttpURLConnectionの使用して明示的に設定されていない場合は、お使いの接続は永久的な陳腐な状態に入ることができます。デフォルトでは。だから、常に「何か」にsetReadTimeoutを設定するか、(どのようにあなたのアプリケーションの実行に応じて、可能性とスレッド)の接続を孤立かもしれません。
最終的な答えがあるので:GCはうまくやっていた、それが遅れの責任を負いませんでした。スレッドは単に私が読み取りタイムアウトを設定していなかったので、単一の番号でFOREVER立ち往生、およびのでされたisWorkingProxy()
方法の結果を得ていないと読んで保たれません。