Рассмотрим этот код:
package com.zip;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Date;
import static com.diffplug.common.base.Errors.rethrow;
/**
* @author nsheremet
*/
public class ParallelDownload2 {
public static int THREADCOUNT = 20;
private static final String URL = "https://server.com/myfile.zip";
public static String OUTPUT = "C:\\!deleteme\\myfile.zip";
public static void main(String[] args) throws Exception {
System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
System.out.println(new Date());
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet(URL);
request.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36");
CloseableHttpResponse response = rethrow().wrap(() -> httpClient.execute(request)).get();
Long contentLength = Long.parseLong(response.getFirstHeader("Content-Length").getValue());
long blocksize = contentLength / THREADCOUNT;
RandomAccessFile randomAccessFile = new RandomAccessFile(new File(OUTPUT), "rwd");
randomAccessFile.setLength(contentLength);
randomAccessFile.close();
response.close();
for (long i = 0; i <THREADCOUNT; i++) {
long startpos = i * blocksize;
long endpos = (i + 1) * blocksize - 1;
if (i == THREADCOUNT - 1) {
endpos = contentLength;
}
new Thread(new DownloadTask(i, startpos, endpos)).start();
}
System.out.println(new Date());
}
public static class DownloadTask implements Runnable {
public DownloadTask(
long id,
long startpos,
long endpos
) {
this.id = id;
this.startpos = startpos;
this.endpos = endpos;
}
long id;
long startpos;
long endpos;
@Override
public void run() {
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet(URL);
request.addHeader("Range", "bytes=" + startpos + "-" + endpos + "");
request.addHeader("Connection", "keep-alive");
request.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36");
CloseableHttpResponse response = rethrow().wrap(() -> httpClient.execute(request)).get();
if (response.getStatusLine().getStatusCode() == 206) {
InputStream is = response.getEntity().getContent();
RandomAccessFile randomAccessFile = new RandomAccessFile(new File(OUTPUT), "rwd");
randomAccessFile.seek(startpos);
int len = 0;
byte[] buffer = new byte[1024*10];
while ((len = is.read(buffer)) != -1) {
randomAccessFile.write(buffer, 0, len);
}
is.close();
randomAccessFile.close();
System.out.println("Thread "+ Thread.currentThread().getId() +": Download");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new Date());
}
}
}
Это модифицированная копия этой , которая написана простым URL.openConnection
. Почему URL.openConnection
с многопоточностью не загружает файл со скоростью 10 Мбит / с c, тогда как скорость версии apach http-клиента в основном составляет 1-5 Мбит / с c? Я что-то пропустил в настройках клиента http apache?
ОБНОВЛЕН
- Я использую несколько HttpClients, потому что один объект приводит к той же производительности, что и 1 соединение через URL
- Http apache клиент используется в высокопроизводительных серверах, поэтому я считаю, что есть определенная проблема конфигурации. Но что именно?
О коде
Это, конечно, не готовый к работе код, и его следует рассматривать как прототип, где я хочу, чтобы загрузка многопоточности работала быстро.
О многопоточности
Я не могу объяснить, почему, поскольку я не являюсь владельцем загружаемого ресурса, но многопотоковая скорость загрузки намного быстрее (в 10 раз) одного потока.