Оптимизируют ли файловые дескрипторы запись в файлы?

Вы можете прекратить использование файла подкачки и занять память другими программами.

swapoff -a

Для получения дополнительной информации прочтите man swapon или man swapoff

Или настройте виртуальную машину с меньшим объемом оперативной памяти. Это немного больше работы, но, вероятно, полезно в долгосрочной перспективе, но означает, что вам нужен ЦП, поддерживающий виртуальные машины.

7
19.05.2018, 12:18
3 ответа

La principal diferencia entre abrir el archivo antes del ciclo con execy poner la redirección en el comando en el ciclo es que el primero requiere configurar el descriptor de archivo solo una vez, mientras que el segundo abre y cierra el archivo para cada iteración del bucle.

Es probable que hacerlo una vez sea más eficiente, pero si tuviera que ejecutar un comando externo dentro del ciclo, la diferencia probablemente desaparecería en el costo de ejecutar el comando.(echoaquí probablemente esté integrado, por lo que no se aplica)

Si la salida se va a enviar a algo que no sea un archivo normal (p. si xes una tubería con nombre ), el acto de abrir y cerrar el archivo puede ser visible para otros procesos, por lo que también puede haber diferencias en el comportamiento.


Tenga en cuenta que realmente no hay diferencia entre una redirección a través de execy una redirección en el comando, ambos abren el archivo y hacen malabarismos con los números de descriptor de archivo.

Estos dos deberían ser bastante equivalentes, ya que ambos open()el archivo y write()a él. (Sin embargo, hay diferencias en cómo se almacena fd 1 durante la duración del comando.):

for i in {1..1000}; do 
    >>x echo "$i"
done


for i in {1..1000}; do
    exec 3>&1 1>>x         # assuming fd 3 is available
    echo "$i"              # here, fd 3 is visible to the command
    exec 1>&3 3>&-
done

12
27.01.2020, 20:14

Sí, es más eficiente

La forma más fácil de probar es aumentar el conteo para decir 500000 y cronometrarlo:

> time bash s1.sh; time bash s2.sh
bash s1.sh  16,47s user 10,00s system 99% cpu 26,537 total
bash s2.sh  10,51s user 3,50s system 99% cpu 14,008 total

strace (1 )revela por qué (tenemos uno simple write, en lugar de open+5*fcntl+2*dup+2*close+write):

para for i in {1..1000}; do >>x echo "$i"; doneobtenemos:

open("x", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
write(1, "997\n", 4)                    = 4
dup2(10, 1)                             = 1
fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0
open("x", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
write(1, "998\n", 4)                    = 4
dup2(10, 1)                             = 1
fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0
open("x", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
write(1, "999\n", 4)                    = 4
dup2(10, 1)                             = 1
fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0
open("x", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
fcntl(1, F_GETFD)                       = 0
fcntl(1, F_DUPFD, 10)                   = 10
fcntl(1, F_GETFD)                       = 0
fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
dup2(3, 1)                              = 1
close(3)                                = 0
write(1, "1000\n", 5)                   = 5
dup2(10, 1)                             = 1
fcntl(10, F_GETFD)                      = 0x1 (flags FD_CLOEXEC)
close(10)                               = 0

mientras que para exec 3>&1 1>xquedamos mucho más limpios

write(1, "995\n", 4)                    = 4
write(1, "996\n", 4)                    = 4
write(1, "997\n", 4)                    = 4
write(1, "998\n", 4)                    = 4
write(1, "999\n", 4)                    = 4
write(1, "1000\n", 5)                   = 5

Pero tenga en cuenta que la diferencia no se debe a "usar un FD", sino al lugar donde realiza la redirección. Por ejemplo, si tuviera que hacer for i in {1..1000}; do echo "$i"; done > x, obtendría prácticamente el mismo rendimiento que su segundo ejemplo:

bash s3.sh  10,35s user 3,70s system 100% cpu 14,042 total
7
27.01.2020, 20:14

Para resumir las cosas y agregar un poco de información nueva en este hilo, aquí hay una comparación de cuatro formas de hacerlo, ordenadas por eficiencia. Estimo la eficiencia por medición de tiempo (usuario + sys )para 1 millón de iteraciones, basado en dos series de prueba.

  1. Estos dos son casi iguales :
    • Simple >redirección de bucle (tiempo:100%)
    • Usando execuna vez para todo el ciclo (tiempo:~100%)
  2. Usando >>para cada iteración (tiempo:200% -250%)
  3. Usando execpara cada iteración (tiempo:340% -480%)

La conclusión es esta:

Hay una pequeña diferencia entre usar execy redirecciones simples como >>. (Lo simple es más barato ). No se muestra en el nivel de ejecución de un solo comando, pero con una gran cantidad de repeticiones, la diferencia se vuelve visible. Aunque el peso de ejecución del comando redirigió a las sombras las diferencias, como lo notó ikkachu en la otra respuesta.

0
27.01.2020, 20:14

Теги

Похожие вопросы