나는 검사가 프록시 프록시를 사용하여 HTTP 요청을 전송하여 작업하는 경우 것이 자바 소프트웨어의 조각을 작성했습니다.
그런 다음 그들이가 작동하는지 확인을 시도, 데이터베이스에서 30,000 프록시를합니다. 사용되는 데이터베이스에서받은 프록시는 반환 할 ArrayList<String>
만 변경 한 Deque<String>
아래에 명시된 이유.
프로그램이 작동하는 방법은이 것입니다 ProxyRequest
저장 String로서 IP 및 포트가 각각 int로하는 것이 객체. ProxyRequest
객체는 방법이 isWorkingProxy()
시도가 프록시와 리턴한다 사용하여 요청을 보낼 boolean
성공 여부에있다.
이 ProxyRequest
개체는에 의해 감싸되는 RunnableProxyRequest
객체 호출이 super.isWorkingProxy()
오버라이드의 run()
방법. 의 응답을 기반 super.isWorkingProxy()
의 RunnableProxyRequest
객체는 MySQL 데이터베이스를 업데이트합니다.
MySQL 데이터베이스의 업데이트가 있습니다를 수행합니다 synchronized()
.
그것은 FixedThreadPool (A VPS에)를 사용하여 750 개 스레드에서 실행되지만 끝으로, 아주 천천히 (붙어 ~ 50 개 스레드) 분명히 수집기가 작동 쓰레기를 내포된다. 이게 문제 야.
나는 그것이 작동하지 않는 것, 지연을 개선하기 위해 다음을 시도했다 :
1)를 사용하여 Deque<String>
프록시 및 사용 Deque.pop()
수득 String
프록시이다하여. 이 (내가 믿는), 지속적으로하게 Deque<String>
GC에 의한 개선해야하는 작은 지연.
2)을 설정 con.setConnectTimeout(this.timeout);
하는 경우, this.timeout = 5000;
이 방법은, 접속 5 초에서의 결과를 반환한다. 그렇지 않은 경우, 스레드가 완료되고 더 이상 스레드에 활성화 될 수 없습니다.
이 외에도, 나는 성능을 향상시킬 수있는 다른 방법을 알고하지 않습니다.
사람이 나를 GC에 의해 스레드의 끝으로 떨어지고 피하기 / 정지 성능을 향상시킬 수있는 방법을 추천 할 수 있습니까? 나는 이것에 대해 유래 질문 (가 알고있는 자바 스레드 처리의 끝으로 천천히가 ),하지만 난이 질문에 모든 노력을하고 나를 위해 일하지 않았다.
시간 내 주셔서 감사합니다.
코드 조각 :
루프는에 스레드를 추가 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가 잘하고 있었다, 그것은 지연에 대한 책임을지지했다. 스레드는 단순히 내가 읽기 시간 제한을 설정하지 않았기 때문에 하나의 숫자에 영원히 갇혀, 그리고 있도록 한 isWorkingProxy()
방법 결과를 얻지 독서 유지 않았다.