Я написал программный продукт на Java, который проверяет, работают ли прокси, отправляя HTTP-запрос с использованием прокси.
Требуется около 30 000 прокси из базы данных, а затем пытается проверить их работоспособность. Прокси, полученные из базы данных, возвращались как ArrayList<String>
, но были изменены на Deque<String>
по причинам, указанным ниже.
Способ работы программы заключается в том, что существует объект ProxyRequest
, в котором IP-адрес и порт хранятся как String и int соответственно. У объекта ProxyRequest
есть метод isWorkingProxy()
, который пытается отправить запрос через прокси-сервер и возвращает boolean
, если он был успешным.
Этот ProxyRequest
объект обернут вокруг RunnableProxyRequest
объекта, который вызывает super.isWorkingProxy()
в переопределенном методе run()
. Основываясь на ответе super.isWorkingProxy()
, объект RunnableProxyRequest
обновляет базу данных MySQL.
Обратите внимание, что обновление базы данных MySQL synchronized()
.
Он работает на 750 потоках, используя FixedThreadPool (на VPS), но в направлении
в конце она становится очень медленной (зависает на ~ 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.
}
}