У меня есть код python, который отправляет данные в сокет (довольно большой файл). Должен ли я разделить его на 1kb куски, или будет только conn.sendall(file.read())
приемлемым?Должен ли я отправлять данные в куски или отправлять их сразу?
ответ
Это будет иметь значение для отправки. (Я предполагаю, что вы используете сокет TCP для целей этой дискуссии.)
При попытке отправить 1K ядро будет принимать этот 1K, скопировать его в ядро TCP-буферы и вернуть успех (и, возможно, начать отправку к сверстнику в то же время). В этот момент вы отправите еще 1K, и произойдет то же самое. В конце концов, если файл достаточно велик, и сеть не может отправить его достаточно быстро или приемник не сможет его слить достаточно быстро, пространство буфера ядра, используемое вашими данными, достигнет некоторого внутреннего предела, и ваш процесс будет заблокирован до тех пор, пока приемник истощает достаточное количество данных. (Это ограничение часто может быть довольно высоким при использовании TCP - в зависимости от ОС, вы можете отправить мегабайт или два, не нажимая его.)
Если вы попытаетесь отправить одним выстрелом, произойдет следующее: данные будут перенесены из вашего буфера в буферы ядра до тех пор, пока не будет достигнут какой-либо предел. В этот момент ваш процесс будет заблокирован до тех пор, пока приемник не удалит данные (и т. Д.).
Однако с помощью первого механизма вы можете отправить файл любого размера без использования неоправданных объемов памяти - ваш буфер в памяти (не включая буферы TCP ядра) должен быть длиной 1 КБ. С sendall
подход file.read()
прочитает весь файл в памяти вашей программы. Если вы попытаетесь сделать это с действительно гигантским файлом (скажем, 40G или что-то еще), это может занять больше памяти, чем у вас, даже включая пространство подкачки.
Итак, в качестве механизма общего назначения я бы определенно поддержал первый подход. Однако для современных архитектур я бы использовал более крупный размер буфера, чем 1K. Точное число, вероятно, не слишком критично; но вы можете выбрать что-то, что поместит сразу несколько блоков диска, скажем, 256K.
И какой размер прочтений вы бы предложили на принимающей стороне? – RomaValcer
Такой же общий подход: я бы использовал достаточно большой, но не огромный буфер (64K или 256K). Из-за того, как работает TCP, вы можете получить буферы, которые только частично заполнены. Но просто добавьте каждый кусок, полученный напрямую в файл. (Ядро уже имеет хорошо оптимизированный код для агрегирования последовательно написанных буферов, а добавление буферов на питоне просто приводит к ненужным дополнительным копиям памяти.) –