Considere el siguiente escenario. Tengo dos programas A y B. El programa A sale a líneas de cadenas estándar mientras que el programa B procesa líneas desde stdin. La forma de usar estos dos programas es, por supuesto:
foo @ bar: ~ $ A | si
Ahora he notado que esto solo consume un núcleo; Por eso me pregunto:
¿Los programas A y B comparten los mismos recursos computacionales? Si es así, ¿hay alguna manera de ejecutar A y B al mismo tiempo?
Otra cosa que he notado es que A se ejecuta mucho más rápido que B, por lo tanto, me pregunto si de alguna manera podría ejecutar más programas B y dejar que procesen las líneas que A genera en paralelo.
Es decir, A generaría sus líneas, y habría N instancias de programas B que leerían estas líneas (quien las lea primero) las procesaría y generaría en stdout.
Entonces mi pregunta final es:
¿Hay alguna manera de canalizar la salida a A entre varios procesos B sin tener que ocuparse de las condiciones de carrera y otras inconsistencias que podrían surgir?
fuente
A | B | C
es paralelo como en procesos separados, debido a la naturaleza de las tuberías (B tiene que esperar la salida de A, C tiene que esperar la salida de B) aún puede ser lineal en algunos casos. Depende completamente de qué tipo de salida producen. No hay muchos casos en los que la ejecución de múltiplesB
ayude mucho, es muy posible que el ejemplo de wc paralelo sea más lento que el normal,wc
ya que dividir puede requerir más recursos que contar líneas normalmente. Usar con cuidado.Respuestas:
Un problema con
split --filter
es que la salida se puede mezclar, por lo que obtiene media línea del proceso 1 seguido de media línea del proceso 2.GNU Parallel garantiza que no habrá confusión.
Así que asume que quieres hacer:
Pero ese B es terriblemente lento y, por lo tanto, quieres paralelizar eso. Entonces puedes hacer:
GNU Paralelo se divide por defecto en \ ny un tamaño de bloque de 1 MB. Esto se puede ajustar con --recend y --block.
Puede encontrar más información sobre GNU Parallel en: http://www.gnu.org/s/parallel/
Puede instalar GNU Parallel en solo 10 segundos con:
Vea el video de introducción en http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
fuente
--block-size
dependerá de la cantidad de RAM y de la rapidez con que pueda comenzar una nuevaB
. En su situación, usaría--block 100M
y vería cómo funciona.sh
, es excelente. El problema radica en pasarlo a sh: descargar y ejecutar código ejecutable desde un sitio . Eso sí, tal vez solo estoy siendo demasiado paranoico, ya que uno podría objetar que un RPM o DEB personalizado es básicamente lo mismo, e incluso publicar el código en una página para copiarlo y pegarlo resultaría en que las personas lo hagan a ciegas de todas formas.Cuando escribe
A | B
, ambos procesos ya se ejecutan en paralelo. Si ve que usan solo un núcleo, probablemente se deba a la configuración de afinidad de la CPU (quizás haya alguna herramienta para generar un proceso con diferente afinidad) o porque un proceso no es suficiente para mantener un núcleo completo, y el sistema " prefiere "no extender la informática.Para ejecutar varias B con una A, necesita una herramienta como
split
con la--filter
opción:Sin embargo, esto puede estropear el orden de las líneas en la salida, porque los trabajos B no se ejecutarán a la misma velocidad. Si esto es un problema, es posible que deba redirigir la salida B i-th a un archivo intermedio y unirlas al final usando
cat
. Esto, a su vez, puede requerir un considerable espacio en disco.Existen otras opciones (por ejemplo, se podría limitar a cada instancia de B a una sola línea de salida de búfer, espere hasta que su conjunto "redondo" de B ha finalizado, ejecute el equivalente de una a reducir a
split
's mapa , ycat
la salida temporal juntos), con diferentes niveles de eficiencia. La opción 'redonda' que se acaba de describir, por ejemplo, esperará a que finalice la instancia más lenta de B , por lo que dependerá en gran medida del almacenamiento en búfer disponible para B;[m]buffer
puede ayudar, o puede que no, dependiendo de cuáles sean las operaciones.Ejemplos
Genere los primeros 1000 números y cuente las líneas en paralelo:
Si tuviéramos que "marcar" las líneas, veríamos que cada primera línea se envía al proceso # 1, cada quinta línea al proceso # 5 y así sucesivamente. Además, en el tiempo que lleva
split
generar el segundo proceso, el primero ya es un buen camino hacia su cuota:Cuando se ejecuta en una máquina de 2 núcleos
seq
,split
y loswc
procesos comparten los núcleos; pero mirando más de cerca, el sistema deja los dos primeros procesos en CPU0 y divide la CPU1 entre los procesos de trabajo:Observe especialmente que se
split
está comiendo una cantidad considerable de CPU. Esto disminuirá en proporción a las necesidades de A; es decir, si A es un proceso más pesado queseq
, la sobrecarga relativa desplit
disminuirá. Pero si A es un proceso muy liviano y B es bastante rápido (por lo que no necesita más de 2-3 B para mantenerse junto con A), entonces la paralelización consplit
(o tuberías en general) bien podría no valer la pena.fuente
split
--filter
falta la opción? En mi Ubuntu 12.04-LTS ("wheezy / sid"), está ahí, y mis ejemplos funcionan. ¿Podría haber instalado uno diferentesplit
al de GNU coreutils?