c networking haskell concurrency green-threads

¿Qué bibliotecas de hilos verdes están disponibles para C que pueden igualar el rendimiento y la facilidad de uso de los hilos verdes de Haskell?



networking concurrency (3)

Use hilos POSIX. Son "verdes" en cualquier implementación moderna, no en el sentido de "hilos verdes", sino en el sentido de ser ligeros y eficientes. No existe una forma portátil de desplegar sus propios hilos encima de los hilos simples C o POSIX sin hilos. Como se mencionó OP, hay algunas bibliotecas que implementan hilos verdes / co-rutinas en formas no portátiles (a menudo a pesar de reclamar la portabilidad).

El enfoque más cercano al portátil es usar makecontext / swapcontext , y desafortunadamente esto no puede funcionar bien porque tiene que hacer syscalls para guardar / restaurar la máscara de señal en cada interruptor entre "hilos". Esto hace que el cambio entre subprocesos "verdes" sea más costoso que un cambio de contexto entre subprocesos de núcleo en una implementación "real" de subprocesos POSIX, y básicamente niega cualquier beneficio reivindicado de "hilos verdes".

Los enfoques no portátiles que no se preocupan por la máscara de señal podrían usar el asm específico de la máquina para realizar los cambios de contexto por completo en el espacio de usuario y, en teoría, funcionan mejor que los subprocesos del núcleo, pero el rendimiento volvería a volar tan pronto como introduce IO, ya que un subproceso que está a punto de realizar IO tendría que hacer primero pruebas costosas para comprobar si la operación se bloqueará y, de ser así, pasar el control a un subproceso diferente.

Mantengo mi posición de que los "hilos verdes" son una idea cuyo tiempo ha pasado hace mucho tiempo. Esta también parece ser la posición de Austin Group (responsable de POSIX), que eliminó las funciones de ucontext en POSIX 2008 y recomendó el reemplazo con hilos POSIX (que ahora son una característica obligatoria).

Estoy acostumbrado a confiar en forkIO de GHC para hilos ligeros portátiles cuando programo en Haskell.

¿Cuáles son las bibliotecas equivalentes para C que pueden proporcionar la misma escalabilidad y facilidad de uso?

Específicamente, necesito C-equivalentes de al menos las dos funciones siguientes.

forkIO :: IO () -> IO ThreadId killThread :: ThreadId -> IO ()

Supongo que para mi aplicación, sería suficiente si los hilos solo activaran operaciones de bloqueo en lugar de suspenderse forzosamente porque todos los hilos bloquean con mucha frecuencia para IO de red y solo uso la llamada del sistema de splice para pedir al kernel de Linux que transfiera datos entre tomas .

Actualizar

Este documento tiene figuras y tablas que comparan

con resultados que favorecen Protothreads. Como no he usado ninguno y puede haber otras bibliotecas, me gustaría saber de cualquiera que haya utilizado / desarrollado dichas bibliotecas.


Ya no tengo los comentarios para el siguiente código, ni ejemplos: esta es una biblioteca de hilos (pseudo) portátil implementada como macros de preprocesador.

typedef struct { unsigned int magic; unsigned short ctx; unsigned char is_destroyed; } _run; typedef struct { unsigned int magic; unsigned int cnt; } _sem; #define aa_RUNNER_WAITING 0 #define aa_RUNNER_YIELDED 1 #define aa_RUNNER_EXITED 2 #define aa_RUNNER_ENDED 3 #define aaRunnerCreate(rp) (rp)->magic=''runr''; (rp)->ctx=0; (rp)->is_destroyed=NO #define aaRunnerDestroy(rp) (rp)->is_destroyed=YES #define aaRunnerThread(args) C args #define aaRunnerBegin(rp) { C yflag=YES; if(yflag) {} switch((rp)->ctx) { case 0: #define aaRunnerEnd(rp) } yflag=NO; if(yflag) {} aaRunnerCreate(rp); return aa_RUNNER_ENDED; } #define aaRunnerWaitUntil(rp,condx) do { (rp)->ctx=__LINE__; case __LINE__: if(!(condx)) { return aa_RUNNER_WAITING; } } while(0) #define aaRunnerWaitWhile(rp,condi) aaRunnerWaitUntil((rp),!(condi)) #define aaRunnerWaitThread(rp,thr) aaRunnerWaitWhile((rp),aaRunnerSchedule(thr)) #define aaRunnerWaitSpawn(rp,chl,thr) do { aaRunnerCreate((chl)); aaRunnerWaitThread((rp),(thr)); } while(0) #define aaRunnerRestart(rp) do { aaRunnerCreate(rp); return aa_RUNNER_WAITING; } while(0) #define aaRunnerExit(rp) do { aaRunnerCreate(rp); (rp)->magic=0; return aa_RUNNER_EXITED; } while(0) #define aaRunnerSchedule(f) ((f)<aa_RUNNER_EXITED) #define aaRunnerYield(rp) do { yflag=NO; (rp)->ctx=__LINE__; case __LINE__: if(!yflag||!((rp)->is_destroyed)) { return aa_RUNNER_YIELDED; } } while(0) #define aaRunnerYieldUntil(rp,condi) do { yflag=NO; (rp)->ctx=__LINE__; case __LINE__: if(!yflag||!(condi)) { return aa_RUNNER_YIELDED; } } while(0) #define aaRunnerSemInit(sp,c) (sp)->magic=''runs''; (sp)->cnt=c #define aaRunnerSemWait(rp,sp) do { aaRunnerWaitUntil(rp,(sp)->cnt>0); --(sp)->cnt; } while(0) #define aaRunnerSemSignal(rp,sp) ++(sp)->cnt


libMill es probablemente lo que está buscando: http://libmill.org/

Implementa subprocesos de nivel de usuario en el estilo de canal Go-Lang.

Y está siendo desarrollado por el súper inteligente Martin Sústrik, creador de ZeroMQ http://250bpm.com/ . Entonces debe ser bueno ☺