Почему мой многопоточный загрузчик сокетов на основе Python работает медленнее, чем мой многопоточный загрузчик, использ ⇐ Python
Почему мой многопоточный загрузчик сокетов на основе Python работает медленнее, чем мой многопоточный загрузчик, использ
Я пытаюсь реализовать многопоточный загрузчик сокетов (с прокси-сервером), но он намного медленнее, чем я ожидал. Поэтому я пытаюсь реализовать это другим способом (запросами). Это быстрее, чем сокет, интересно, почему? Какая причина этого? Какую часть я недопонимаю?
импорт журнала импортировать ОС импортировать повторно импорт сокета импортные носки импорт потоков время импорта из urllib.parse импортировать ParseResult, urlparse, снять кавычки флаг: bool = Истина класс МойПрокси: def __init__(self: "MyProxy", протокол: str, хост: str, порт: int) -> Нет: self.protocol: str = протокол self.host: str = хост self.port: int = порт def setSocks5Proxy(self: "MyProxy", s:socks.socksocket) -> Нет: s.set_proxy(socks.SOCKS5, self.host, self.port) def getHttpProxy(self: "MyProxy") -> str: верните f"{self.protocol}://{self.host}:{self.port}" def getHostName(url: str) -> str | Никто: пытаться: хост: ParseResult = urlparse(url) вернуть хост.имя хоста кроме исключения как e: logging.error(f"ошибка анализа URL:({url}) с {e}") def getFileName(url: str) -> str | Никто: пытаться: хост: ParseResult = urlparse(url) вернуть хост.путь.split("/")[-1] кроме исключения как e: logging.error(f"parseFileName Fail url:({url}) ошибка с {e}") защита download_chunk( URL: str, начало: int, конец: int, dataDict: dict, прокси: MyProxy | Нет = Нет ): хост = getHostName (url) если не хост: глобальный флаг флаг = Ложь если прокси: s = носки.socksocket(socket.AF_INET, сокет.SOCK_STREAM) proxy.setSocks5Прокси(и) еще: s = сокет.сокет(сокет.AF_INET, сокет.SOCK_STREAM) print(threading.current_thread().ident, "start:", time.time()) s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 81920000) s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 81920000) s.connect((хост, 80)) запрос = ( f"GET {url} HTTP/1.1\r\nДиапазон: bytes={start}-{end}\r\nХост: {host}\r\n\r\n" ) s.sendall(request.encode()) ответ = б"" пока правда: данные = s.recv(81920000) если нет данных: перерыв ответ += данные header_delimiter = b"\r\n\r\n" header_end_index = response.find(header_delimiter) если header_end_index != -1: ответ = ответ[header_end_index + len(header_delimiter) :] dataDict[start] = ответ print(threading.current_thread().ident, "конец:", time.time()) # 关闭连接 с.закрыть() def download (url: str, savePath: str, num_threads: int, прокси: MyProxy | None = None): хост: str = getHostName (url) defaultFileName: str = getFileName(url) если прокси: s = носки.socksocket(socket.AF_INET, сокет.SOCK_STREAM) proxy.setSocks5Прокси(и) еще: s = сокет.сокет(сокет.AF_INET, сокет.SOCK_STREAM) s.connect((хост, 80)) request = f"HEAD {url} HTTP/1.1\r\nХост: {хост}\r\n\r\n" s.sendall(request.encode()) ответ = s.recv(4096).decode() имя_файла = re.search(r'Content-Disposition:.*filename="(.+)"', ответ) имя_файла = имя_файла.группа(1), если имя_файла, иначе имя_файла по умолчанию имя файла = снять кавычки (имя файла) content_length = int(response.split("Content-Length: ")[1].split("\r\n")[0]) # print(f"{response}") с.закрыть() logging.info(f"文件名: {filename}, 文件大小: {content_length}") если os.path.isdir(savePath): savePath = os.path.join(savePath, имя файла) элиф os.path.isfile(savePath): logging.warning(f"savePath({savePath}) существует, будет скрыт") еще: logging.error(f"savePath({savePath}) не существует, будет создан") os.madeirs(savePath, Exist_ok=True) savePath = os.path.join(savePath, имя файла) chunk_size = длина_контента // количество_потоков список потоков: список[threading.Thread] = [] dataDict: dict = {} начало = 0 конец = 0 для меня в диапазоне (num_threads): конец = ( (start + chunk_size - 1), если (i < число_потоков — 1) иначе (длина_контента — 1) ) нить = резьба.Thread( target=download_chunk, args=(url, начало, конец, dataDict, прокси) ) поток.start() thread_list.append(поток) начало = конец + 1 для потока в thread_list: поток.join() если нет флага: logging.error("Ошибка загрузки") возвращаться с open(savePath, "wb+") в виде файла: для ключа в сортировке (dataDict.keys()): file.write(dataDict[ключ]) logging.info("Готово!") logging.basicConfig(уровень="ИНФО") startTime = время.время() logging.info(startTime) скачать( url="https://download.zerotier.com/dist/ZeroTier%20One.msi", # url="https://releases.ubuntu.com/20.04.6/ubu ... -amd64.iso", savePath="E:", число_потоков = 8, proxy=MyProxy("socks5", "127.0.0.1", 10808), ) logging.info(time.time() - startTime) выше — мой загрузчик сокетов,
импорт журнала импортировать ОС импорт потоков время импорта запросы на импорт из urllib.parse импортировать urlparse класс МойПрокси: def __init__(self: "MyProxy", протокол: str, хост: str, порт: int) -> Нет: self.protocol: str = протокол self.host: str = хост self.port: int = порт def getHttpProxy(self: "MyProxy") -> str: верните f"{self.protocol}://{self.host}:{self.port}" класс DownloadThread(threading.Thread): защита __init__( я: "DownloadThread", URL: ул., начальный_байт: интервал, конечный_байт: интервал, имя файла: ул, прокси: dict | Нет = Нет, ) -> Нет: threading.Thread.__init__(self) self.url = URL self.start_byte = стартовый_байт self.end_byte = конечный_байт self.filename = имя файла self.proxies = прокси def run(self: "DownloadThread"): headers = {"Диапазон": f"bytes={self.start_byte}-{self.end_byte}"} ответ = запросы.получить(# noqa: S113 self.url, headers=заголовки, прокси=self.proxies ) с open(self.filename, "r+b") в качестве файла: file.seek(self.start_byte) file.write(ответ.контент) print(f"Загружено {self.filename} байт {self.start_byte}-{self.end_byte}") def main(url: str, savePath: str, num_threads: int = 1, proxy: MyProxy | None = None): имя_файла = urlparse(os.path.basename(url)).path # 判断保存路径 если os.path.isdir(savePath): savePath = os.path.join(savePath, имя файла) элиф os.path.isfile(savePath): logging.warning(f"savePath({savePath}) существует, будет скрыт") еще: logging.error(f"savePath({savePath}) не существует, будет создан") os.madeirs(savePath, Exist_ok=True) savePath = os.path.join(savePath, имя файла) прокси = Нет если прокси: прокси = {"http": proxy.getHttpProxy(), "https": proxy.getHttpProxy()} ответ = запросы.head(url, таймаут=60, прокси=прокси) total_size = int(response.headers.get("Content-Length", 0)) print("total_size:", total_size) part_size = total_size // количество_потоков темы = [] с open(savePath, "wb"): проходить для меня в диапазоне (num_threads): начальный_байт = размер_части * я конечный_байт = общий_размер, если я == число_потоков - 1, иначе начальный_байт + размер_части - 1 поток: DownloadThread = DownloadThread( URL, start_byte, end_byte, savePath, прокси ) поток.start() threads.append(поток) за т в темах: t.join() print("Загрузка завершена") если __name__ == "__main__": start_time = время.время() основной( # url="https://releases.ubuntu.com/20.04.6/ubu ... -amd64.iso", # url="https://zenlayer.dl.sourceforge.net/pro ... _Win64.exe", url="https://saimei.ftp.acc.umu.se/cdimage/a ... etinst.iso", savePath="E:\\", число_потоков = 1, proxy=MyProxy("http", "127.0.0.1", 10809), ) конечное_время = время.время() print(f"耗时: {end_time - start_time} 秒") выше — загрузчик моего запроса, В большинстве случаев запросы выполняются быстрее, чем загрузчик сокетов. какая часть является причиной того, что мой загрузчик сокетов работает так медленно?
я пытаюсь использовать s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 81920000), чтобы увеличить размер буфера, но это не работает
Я пытаюсь реализовать многопоточный загрузчик сокетов (с прокси-сервером), но он намного медленнее, чем я ожидал. Поэтому я пытаюсь реализовать это другим способом (запросами). Это быстрее, чем сокет, интересно, почему? Какая причина этого? Какую часть я недопонимаю?
импорт журнала импортировать ОС импортировать повторно импорт сокета импортные носки импорт потоков время импорта из urllib.parse импортировать ParseResult, urlparse, снять кавычки флаг: bool = Истина класс МойПрокси: def __init__(self: "MyProxy", протокол: str, хост: str, порт: int) -> Нет: self.protocol: str = протокол self.host: str = хост self.port: int = порт def setSocks5Proxy(self: "MyProxy", s:socks.socksocket) -> Нет: s.set_proxy(socks.SOCKS5, self.host, self.port) def getHttpProxy(self: "MyProxy") -> str: верните f"{self.protocol}://{self.host}:{self.port}" def getHostName(url: str) -> str | Никто: пытаться: хост: ParseResult = urlparse(url) вернуть хост.имя хоста кроме исключения как e: logging.error(f"ошибка анализа URL:({url}) с {e}") def getFileName(url: str) -> str | Никто: пытаться: хост: ParseResult = urlparse(url) вернуть хост.путь.split("/")[-1] кроме исключения как e: logging.error(f"parseFileName Fail url:({url}) ошибка с {e}") защита download_chunk( URL: str, начало: int, конец: int, dataDict: dict, прокси: MyProxy | Нет = Нет ): хост = getHostName (url) если не хост: глобальный флаг флаг = Ложь если прокси: s = носки.socksocket(socket.AF_INET, сокет.SOCK_STREAM) proxy.setSocks5Прокси(и) еще: s = сокет.сокет(сокет.AF_INET, сокет.SOCK_STREAM) print(threading.current_thread().ident, "start:", time.time()) s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 81920000) s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 81920000) s.connect((хост, 80)) запрос = ( f"GET {url} HTTP/1.1\r\nДиапазон: bytes={start}-{end}\r\nХост: {host}\r\n\r\n" ) s.sendall(request.encode()) ответ = б"" пока правда: данные = s.recv(81920000) если нет данных: перерыв ответ += данные header_delimiter = b"\r\n\r\n" header_end_index = response.find(header_delimiter) если header_end_index != -1: ответ = ответ[header_end_index + len(header_delimiter) :] dataDict[start] = ответ print(threading.current_thread().ident, "конец:", time.time()) # 关闭连接 с.закрыть() def download (url: str, savePath: str, num_threads: int, прокси: MyProxy | None = None): хост: str = getHostName (url) defaultFileName: str = getFileName(url) если прокси: s = носки.socksocket(socket.AF_INET, сокет.SOCK_STREAM) proxy.setSocks5Прокси(и) еще: s = сокет.сокет(сокет.AF_INET, сокет.SOCK_STREAM) s.connect((хост, 80)) request = f"HEAD {url} HTTP/1.1\r\nХост: {хост}\r\n\r\n" s.sendall(request.encode()) ответ = s.recv(4096).decode() имя_файла = re.search(r'Content-Disposition:.*filename="(.+)"', ответ) имя_файла = имя_файла.группа(1), если имя_файла, иначе имя_файла по умолчанию имя файла = снять кавычки (имя файла) content_length = int(response.split("Content-Length: ")[1].split("\r\n")[0]) # print(f"{response}") с.закрыть() logging.info(f"文件名: {filename}, 文件大小: {content_length}") если os.path.isdir(savePath): savePath = os.path.join(savePath, имя файла) элиф os.path.isfile(savePath): logging.warning(f"savePath({savePath}) существует, будет скрыт") еще: logging.error(f"savePath({savePath}) не существует, будет создан") os.madeirs(savePath, Exist_ok=True) savePath = os.path.join(savePath, имя файла) chunk_size = длина_контента // количество_потоков список потоков: список[threading.Thread] = [] dataDict: dict = {} начало = 0 конец = 0 для меня в диапазоне (num_threads): конец = ( (start + chunk_size - 1), если (i < число_потоков — 1) иначе (длина_контента — 1) ) нить = резьба.Thread( target=download_chunk, args=(url, начало, конец, dataDict, прокси) ) поток.start() thread_list.append(поток) начало = конец + 1 для потока в thread_list: поток.join() если нет флага: logging.error("Ошибка загрузки") возвращаться с open(savePath, "wb+") в виде файла: для ключа в сортировке (dataDict.keys()): file.write(dataDict[ключ]) logging.info("Готово!") logging.basicConfig(уровень="ИНФО") startTime = время.время() logging.info(startTime) скачать( url="https://download.zerotier.com/dist/ZeroTier%20One.msi", # url="https://releases.ubuntu.com/20.04.6/ubu ... -amd64.iso", savePath="E:", число_потоков = 8, proxy=MyProxy("socks5", "127.0.0.1", 10808), ) logging.info(time.time() - startTime) выше — мой загрузчик сокетов,
импорт журнала импортировать ОС импорт потоков время импорта запросы на импорт из urllib.parse импортировать urlparse класс МойПрокси: def __init__(self: "MyProxy", протокол: str, хост: str, порт: int) -> Нет: self.protocol: str = протокол self.host: str = хост self.port: int = порт def getHttpProxy(self: "MyProxy") -> str: верните f"{self.protocol}://{self.host}:{self.port}" класс DownloadThread(threading.Thread): защита __init__( я: "DownloadThread", URL: ул., начальный_байт: интервал, конечный_байт: интервал, имя файла: ул, прокси: dict | Нет = Нет, ) -> Нет: threading.Thread.__init__(self) self.url = URL self.start_byte = стартовый_байт self.end_byte = конечный_байт self.filename = имя файла self.proxies = прокси def run(self: "DownloadThread"): headers = {"Диапазон": f"bytes={self.start_byte}-{self.end_byte}"} ответ = запросы.получить(# noqa: S113 self.url, headers=заголовки, прокси=self.proxies ) с open(self.filename, "r+b") в качестве файла: file.seek(self.start_byte) file.write(ответ.контент) print(f"Загружено {self.filename} байт {self.start_byte}-{self.end_byte}") def main(url: str, savePath: str, num_threads: int = 1, proxy: MyProxy | None = None): имя_файла = urlparse(os.path.basename(url)).path # 判断保存路径 если os.path.isdir(savePath): savePath = os.path.join(savePath, имя файла) элиф os.path.isfile(savePath): logging.warning(f"savePath({savePath}) существует, будет скрыт") еще: logging.error(f"savePath({savePath}) не существует, будет создан") os.madeirs(savePath, Exist_ok=True) savePath = os.path.join(savePath, имя файла) прокси = Нет если прокси: прокси = {"http": proxy.getHttpProxy(), "https": proxy.getHttpProxy()} ответ = запросы.head(url, таймаут=60, прокси=прокси) total_size = int(response.headers.get("Content-Length", 0)) print("total_size:", total_size) part_size = total_size // количество_потоков темы = [] с open(savePath, "wb"): проходить для меня в диапазоне (num_threads): начальный_байт = размер_части * я конечный_байт = общий_размер, если я == число_потоков - 1, иначе начальный_байт + размер_части - 1 поток: DownloadThread = DownloadThread( URL, start_byte, end_byte, savePath, прокси ) поток.start() threads.append(поток) за т в темах: t.join() print("Загрузка завершена") если __name__ == "__main__": start_time = время.время() основной( # url="https://releases.ubuntu.com/20.04.6/ubu ... -amd64.iso", # url="https://zenlayer.dl.sourceforge.net/pro ... _Win64.exe", url="https://saimei.ftp.acc.umu.se/cdimage/a ... etinst.iso", savePath="E:\\", число_потоков = 1, proxy=MyProxy("http", "127.0.0.1", 10809), ) конечное_время = время.время() print(f"耗时: {end_time - start_time} 秒") выше — загрузчик моего запроса, В большинстве случаев запросы выполняются быстрее, чем загрузчик сокетов. какая часть является причиной того, что мой загрузчик сокетов работает так медленно?
я пытаюсь использовать s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 81920000), чтобы увеличить размер буфера, но это не работает
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Использование параллелизма в Java делает программу медленнее (в четыре раза медленнее!)
Anonymous » » в форуме JAVA - 0 Ответы
- 8 Просмотры
-
Последнее сообщение Anonymous
-