Ответ 1
sendfile
был с тех пор и по-прежнему является нулевым (предполагается, что аппаратное обеспечение позволяет это, но это обычно имеет место). В качестве нулевой копии была вся суть этого сценария в первую очередь. sendfile
теперь реализуется как обертка вокруг splice
.
Это говорит о том, что splice
тоже имеет нулевую копию, и это действительно так. По крайней мере, теоретически и, по крайней мере, в некоторых случаях. Проблема заключается в том, как правильно использовать его, чтобы он работал надежно, и поэтому он имеет нулевую копию. Документация... разрежена, по меньшей мере.
В частности, splice
работает только с нулевой копией, если страницы были даны как "подарок", т.е. вы больше не владеете ими (формально, но на самом деле вы все еще это делаете). Это не проблема, если вы просто соедините файловый дескриптор с сокетом, но это большая проблема, если вы хотите объединить данные из адресного пространства вашего приложения или из одного канала в другой. Непонятно, что делать со страницами после (и когда). В документации указано, что впоследствии вы не можете прикасаться к страницам или делать что-либо с ними, никогда, никогда. Поэтому, если вы следуете букве документации, вы должны пропустить память.
Это явно не правильно (это не может быть), но нет хорошего способа узнать (для вас хотя бы!), Когда он безопасен для повторного использования или выпуска этой памяти. Ядро, выполняющее sendfile
, будет знать, поскольку, как только он получает TCP ACK, он знает, что данные больше никогда не нужны. Проблема в том, что вы никогда не увидите ACK. Все, что вы знаете, когда splice
вернулось, - это то, что данные были приняты для отправки (но вы не знаете, было ли оно уже отправлено или получено, или когда это произойдет).
Это означает, что вам нужно как-то понять это на уровне приложений, либо выполнив ручные ACK (поставляется бесплатно с надежным UDP), либо предположив, что если другая сторона отправит ответ на ваш запрос, они, очевидно, должны получить запрос.
Еще одна вещь, с которой вам нужно справиться, - это конечное пространство трубы. По умолчанию очень мало, но даже если вы увеличиваете размер, вы не можете просто наивно спланировать файл любого размера. sendfile
с другой стороны просто позволит вам сделать это, что здорово.
В целом, sendfile
хорош, потому что он просто работает, и он работает хорошо, и вам не нужно заботиться ни о какой из вышеперечисленных деталей. Это не панацея, но это, безусловно, отличное дополнение.
Я лично остался бы в стороне от splice
и его семьи до тех пор, пока все это не будет пересмотрено и пока не станет на 100% ясно, что вы должны делать (и когда) и что вам не нужно делать.
Реальные, эффективные прибыли по сравнению с обычным старым write
в любом случае являются маргинальными для большинства приложений. Я вспоминаю несколько менее вежливых комментариев г-на Торвальдса несколько лет назад (когда BSD имел форму write
, которая сделала бы магию с переназначением страниц, чтобы получить нуль-копию, а Linux не сделал), в которой указывалось, что создание копия обычно не является проблемой, но играть с трюками со страницами не будет [здесь].