stringtranslate.com

Futuros y promesas

En informática , future , promise , delay y deferred hacen referencia a construcciones utilizadas para sincronizar la ejecución de programas en algunos lenguajes de programación concurrente . Describen un objeto que actúa como proxy de un resultado que inicialmente es desconocido, generalmente porque el cálculo de su valor aún no está completo.

El término promesa fue propuesto en 1976 por Daniel P. Friedman y David Wise, [1] y Peter Hibbard lo llamó eventual . [2] Un concepto algo similar, futuro, fue introducido en 1977 en un artículo de Henry Baker y Carl Hewitt . [3]

Los términos future , promise , delay y deferred se usan a menudo indistintamente, aunque a continuación se tratan algunas diferencias de uso entre future y promise . Específicamente, cuando se distingue el uso, un future es una vista de marcador de posición de solo lectura de una variable, mientras que promise es un contenedor de asignación única escribible que establece el valor del future. En particular, un future se puede definir sin especificar qué promesa específica establecerá su valor, y diferentes promesas posibles pueden establecer el valor de un future dado, aunque esto solo se puede hacer una vez para un future dado. En otros casos, un future y una promise se crean juntos y se asocian entre sí: el future es el valor, la promise es la función que establece el valor, esencialmente el valor de retorno (futuro) de una función asincrónica (promesa). Establecer el valor de un future también se llama resolverlo , cumplirlo o vincularlo .

Aplicaciones

Los futuros y las promesas se originaron en la programación funcional y paradigmas relacionados (como la programación lógica ) para disociar un valor (un futuro) de cómo se calculó (una promesa), lo que permite que el cálculo se realice de manera más flexible, en particular al paralelizarlo. Más tarde, encontró uso en la computación distribuida , para reducir la latencia de los viajes de ida y vuelta de la comunicación. Más tarde aún, ganó más uso al permitir escribir programas asincrónicos en estilo directo , en lugar de en estilo de paso de continuación .

Implícito vs. explícito

El uso de futuros puede ser implícito (cualquier uso del futuro obtiene automáticamente su valor, como si fuera una referencia ordinaria ) o explícito (el usuario debe llamar a una función para obtener el valor, como el getmétodo de java.util.concurrent.Futureen Java ). La obtención del valor de un futuro explícito puede denominarse stinging o forcing . Los futuros explícitos pueden implementarse como una biblioteca, mientras que los futuros implícitos suelen implementarse como parte del lenguaje.

El artículo original de Baker y Hewitt describió futuros implícitos, que son compatibles de forma natural con el modelo de actor de computación y los lenguajes de programación orientados a objetos puros como Smalltalk . El artículo de Friedman y Wise describió solo futuros explícitos, probablemente reflejando la dificultad de implementar de manera eficiente futuros implícitos en hardware estándar. La dificultad es que el hardware estándar no maneja futuros para tipos de datos primitivos como números enteros. Por ejemplo, una instrucción add no sabe cómo manejar . En lenguajes de actor u objeto puros, este problema se puede resolver enviando el mensaje , que le pide al futuro que se agregue a sí mismo y devuelva el resultado. Tenga en cuenta que el enfoque de paso de mensajes funciona independientemente de cuándo finalice el cálculo y que no se necesita picar ni forzar.3 + future factorial(100000)future factorial(100000)+[3]3factorial(100000)

Canalización de promesas

El uso de futuros puede reducir drásticamente la latencia en sistemas distribuidos . Por ejemplo, los futuros permiten la segmentación de promesas , [4] [5] tal como se implementa en los lenguajes E y Joule , que también se denominaba flujo de llamadas [6] en el lenguaje Argus .

Considere una expresión que involucre llamadas a procedimientos remotos convencionales , como:

t3 := (xa()).c(yb())

que podría ampliarse a

t1 := xa(); t2 := yb(); t3 := t1.c(t2);

Cada instrucción necesita que se envíe un mensaje y se reciba una respuesta antes de que pueda continuar la siguiente instrucción. Supongamos, por ejemplo, que x, y, t1y t2están todos ubicados en la misma máquina remota. En este caso, deben realizarse dos viajes de ida y vuelta completos de la red a esa máquina antes de que pueda comenzar a ejecutarse la tercera instrucción. La tercera instrucción provocará entonces otro viaje de ida y vuelta a la misma máquina remota.

Usando futuros, la expresión anterior podría escribirse

t3 := (x <- a()) <- c(y <- b())

que podría ampliarse a

t1 := x <- a(); t2 := y <- b(); t3 := t1 <- c(t2);

La sintaxis utilizada aquí es la del lenguaje E, donde x <- a()significa enviar el mensaje a()de forma asincrónica a x. A las tres variables se les asignan inmediatamente futuros para sus resultados, y la ejecución procede a las instrucciones subsiguientes. Los intentos posteriores de resolver el valor de t3pueden causar una demora; sin embargo, la canalización puede reducir la cantidad de viajes de ida y vuelta necesarios. Si, como en el ejemplo anterior, x, , y yestán todos ubicados en la misma máquina remota, una implementación canalizada puede realizar el cálculo con un viaje de ida y vuelta en lugar de tres. Debido a que los tres mensajes están destinados a objetos que están en la misma máquina remota, solo se necesita enviar una solicitud y solo se necesita recibir una respuesta que contenga el resultado. El envío no se bloquearía incluso si y estuvieran en máquinas diferentes entre sí, o para o .t1t2t3t1 <- c(t2)t1t2xy

La canalización de promesas debe distinguirse del paso de mensajes asíncrono en paralelo. En un sistema que admita el paso de mensajes en paralelo pero no la canalización, el mensaje se envía x <- a()y y <- b()en el ejemplo anterior podría realizarse en paralelo, pero el envío de t1 <- c(t2)tendría que esperar hasta que se hubieran recibido tanto como , incluso cuando t1, , y están en la misma máquina remota. La ventaja de latencia relativa de la canalización se vuelve aún mayor en situaciones más complicadas que involucran muchos mensajes.t2xyt1t2

La canalización de promesas tampoco debe confundirse con el procesamiento de mensajes canalizado en sistemas de actores, donde es posible que un actor especifique y comience a ejecutar un comportamiento para el próximo mensaje antes de haber completado el procesamiento del mensaje actual.

Vistas de solo lectura

En algunos lenguajes de programación como Oz , E y AmbientTalk , es posible obtener una vista de solo lectura de un futuro, que permite leer su valor cuando se resuelve, pero no permite resolverlo:

La compatibilidad con vistas de solo lectura es coherente con el principio de privilegio mínimo , ya que permite restringir la capacidad de establecer el valor a los sujetos que necesitan establecerlo. En un sistema que también admite la canalización, el remitente de un mensaje asincrónico (con resultado) recibe la promesa de solo lectura para el resultado y el destino del mensaje recibe el solucionador.

Futuros específicos de subprocesos

Algunos lenguajes, como Alice ML , definen futuros que están asociados con un hilo específico que calcula el valor del futuro. [9] Este cálculo puede comenzar de manera ansiosa cuando se crea el futuro o de manera diferida cuando se necesita su valor por primera vez. Un futuro diferido es similar a un thunk , en el sentido de un cálculo retrasado.

Alice ML también admite futuros que pueden ser resueltos por cualquier hilo y los llama promesas . [8] Este uso de promesa es diferente de su uso en E como se describió anteriormente. En Alice, una promesa no es una vista de solo lectura y la segmentación de promesas no es compatible. En cambio, la segmentación ocurre naturalmente para futuros, incluidos aquellos asociados con promesas.

Semántica de bloqueo vs. semántica de no bloqueo

Si se accede al valor de un futuro de forma asincrónica, por ejemplo, enviándole un mensaje o esperándolo explícitamente mediante una construcción como whenen E, no hay ninguna dificultad en esperar hasta que se resuelva el futuro antes de poder recibir el mensaje o de que se complete la espera. Este es el único caso que se debe considerar en sistemas puramente asincrónicos, como los lenguajes de actores puros.

Sin embargo, en algunos sistemas también puede ser posible intentar acceder de forma inmediata o sincrónica al valor de un futuro. En ese caso, hay que tomar una decisión de diseño:

Como ejemplo de la primera posibilidad, en C++11 , un hilo que necesita el valor de un futuro puede bloquearse hasta que esté disponible llamando a las funciones miembro wait()o get(). También se puede especificar un tiempo de espera en la espera utilizando las funciones miembro wait_for()o wait_until()para evitar un bloqueo indefinido. Si el futuro surgió de una llamada a , std::asyncentonces una espera de bloqueo (sin un tiempo de espera) puede provocar la invocación sincrónica de la función para calcular el resultado en el hilo que espera.

Construcciones relacionadas

Los futuros son un caso particular de la primitiva de sincronización " eventos ", que pueden completarse sólo una vez. En general, los eventos pueden restablecerse al estado inicial vacío y, por lo tanto, completarse tantas veces como se desee. [11]

Una I-var (como en el lenguaje Id ) es un futuro con semántica de bloqueo como la definida anteriormente. Una I-estructura es una estructura de datos que contiene I-vars. Una construcción de sincronización relacionada que se puede configurar varias veces con diferentes valores se denomina M-var . Las M-vars admiten operaciones atómicas para tomar o colocar el valor actual, donde tomar el valor también hace que la M-var vuelva a su estado vacío inicial. [12]

Una variable lógica concurrente [ cita requerida ] es similar a un futuro, pero se actualiza por unificación , de la misma manera que las variables lógicas en la programación lógica . Por lo tanto, se puede vincular más de una vez a valores unificables, pero no se puede volver a establecer en un estado vacío o sin resolver. Las variables de flujo de datos de Oz actúan como variables lógicas concurrentes y también tienen semántica de bloqueo como se mencionó anteriormente.

Una variable de restricción concurrente es una generalización de las variables lógicas concurrentes para respaldar la programación lógica de restricciones : la restricción se puede restringir varias veces, lo que indica conjuntos más pequeños de valores posibles. Por lo general, existe una forma de especificar un procesador que se debe ejecutar siempre que la restricción se reduzca aún más; esto es necesario para respaldar la propagación de restricciones .

Relaciones entre la expresividad de diferentes formas de futuro

Los futuros específicos de subprocesos se pueden implementar de manera directa en futuros no específicos de subprocesos, creando un subproceso para calcular el valor al mismo tiempo que se crea el futuro. En este caso, es conveniente devolver una vista de solo lectura al cliente, de modo que solo el subproceso recién creado pueda resolver este futuro.

Para implementar futuros específicos de subprocesos implícitos perezosos (como los que proporciona Alice ML, por ejemplo) en términos de futuros no específicos de subprocesos, se necesita un mecanismo para determinar cuándo se necesita por primera vez el valor del futuro (por ejemplo, la WaitNeededconstrucción en Oz [13] ). Si todos los valores son objetos, entonces la capacidad de implementar objetos de reenvío transparente es suficiente, ya que el primer mensaje enviado al reenvío indica que se necesita el valor del futuro.

Los futuros no específicos de subprocesos se pueden implementar en futuros específicos de subprocesos, suponiendo que el sistema admita el paso de mensajes, haciendo que el subproceso de resolución envíe un mensaje al propio subproceso del futuro. Sin embargo, esto puede verse como una complejidad innecesaria. En los lenguajes de programación basados ​​en subprocesos, el enfoque más expresivo parece ser proporcionar una combinación de futuros no específicos de subprocesos, vistas de solo lectura y una construcción WaitNeeded o compatibilidad con el reenvío transparente.

Estrategia de evaluación

La estrategia de evaluación de futuros, que puede denominarse call by future (llamada por futuro) , no es determinista: el valor de un futuro se evaluará en algún momento entre el momento en que se crea el futuro y el momento en que se utiliza su valor, pero el momento preciso no se determina de antemano y puede cambiar de una ejecución a otra. El cálculo puede comenzar tan pronto como se crea el futuro ( evaluación ansiosa ) o solo cuando el valor es realmente necesario ( evaluación perezosa ), y puede suspenderse a mitad de camino o ejecutarse en una sola ejecución. Una vez que se asigna el valor de un futuro, no se vuelve a calcular en los futuros accesos; esto es como la memorización utilizada en call by need (llamada por necesidad ).

AUn futuro perezoso es un futuro que tiene una semántica de evaluación perezosa de manera determinista: el cálculo del valor del futuro comienza cuando el valor se necesita por primera vez, como en una llamada por necesidad. Los futuros perezosos se utilizan en lenguajes cuya estrategia de evaluación no es perezosa por defecto. Por ejemplo, enC++11,estos futuros perezosos se pueden crear pasando lastd::launch::deferredpolítica de lanzamiento astd::async, junto con la función para calcular el valor.

Semántica de futuros en el modelo de actor

En el modelo de actor, una expresión de la forma future <Expression>se define por cómo responde a un Evalmensaje con el entorno E y el cliente C de la siguiente manera: La expresión futura responde al Evalmensaje enviando al cliente C un actor recién creado F (el proxy para la respuesta de evaluación <Expression>) como valor de retorno simultáneamente con el envío <Expression>de un Evalmensaje con el entorno E y el cliente C . El comportamiento predeterminado de F es el siguiente:

Sin embargo, algunos futuros pueden tratar las solicitudes de maneras especiales para proporcionar un mayor paralelismo. Por ejemplo, la expresión 1 + future factorial(n)puede crear un nuevo futuro que se comportará como el número 1+factorial(n). Este truco no siempre funciona. Por ejemplo, la siguiente expresión condicional:

if m>future factorial(n) then print("bigger") else print("smaller")

suspende hasta que el futuro factorial(n)haya respondido a la solicitud preguntando si mes mayor que él mismo.

Historia

Las construcciones de futuro y/o promesa se implementaron por primera vez en lenguajes de programación como MultiLisp y Act 1. El uso de variables lógicas para la comunicación en lenguajes de programación lógica concurrente fue bastante similar a los futuros. Estos comenzaron en Prolog con Freeze e IC Prolog , y se convirtieron en una verdadera primitiva de concurrencia con Relational Language, Concurrent Prolog , cláusulas Horn protegidas (GHC), Parlog , Strand , Vulcan , Janus , Oz-Mozart , Flow Java y Alice ML . La I-var de asignación única de los lenguajes de programación de flujo de datos , que se originó en Id e incluyó en Concurrent ML de Reppy , es muy similar a la variable lógica concurrente.

La técnica de canalización de promesas (utilizando futuros para superar la latencia) fue inventada por Barbara Liskov y Liuba Shrira en 1988, [6] e independientemente por Mark S. Miller , Dean Tribble y Rob Jellinghaus en el contexto del Proyecto Xanadu alrededor de 1989. [14]

El término promesa fue acuñado por Liskov y Shrira, aunque se referían al mecanismo de canalización con el nombre call-stream , que ahora rara vez se utiliza.

Tanto el diseño descrito en el artículo de Liskov y Shrira, como la implementación de la segmentación de promesas en Xanadu, tenían el límite de que los valores de las promesas no eran de primera clase : un argumento o el valor devuelto por una llamada o envío no podía ser directamente una promesa (por lo que el ejemplo de segmentación de promesas dado anteriormente, que utiliza una promesa para el resultado de un envío como argumento para otro, no habría sido directamente expresable en el diseño de flujo de llamadas o en la implementación de Xanadu). Parece que las promesas y los flujos de llamadas nunca se implementaron en ninguna versión pública de Argus, [15] el lenguaje de programación utilizado en el artículo de Liskov y Shrira. El desarrollo de Argus se detuvo alrededor de 1988. [16] La implementación de Xanadu de la segmentación de promesas solo se hizo pública con la publicación del código fuente de Udanax Gold [17] en 1999, y nunca se explicó en ningún documento publicado. [18] Las implementaciones posteriores en Joule y E admiten promesas y solucionadores de primera clase por completo.

Varios de los primeros lenguajes de actores, incluida la serie Act, [19] [20] admitían tanto el paso de mensajes en paralelo como el procesamiento de mensajes segmentados, pero no la segmentación de mensajes (si bien es técnicamente posible implementar la última de estas características en los dos primeros, no hay evidencia de que los lenguajes Act lo hicieran).

Después de 2000, se produjo un importante resurgimiento del interés en futuros y promesas, debido a su uso en la capacidad de respuesta de las interfaces de usuario, y en el desarrollo web , debido al modelo de solicitud-respuesta de paso de mensajes. Varios lenguajes principales ahora tienen soporte de lenguaje para futuros y promesas, más notablemente popularizado por FutureTasken Java 5 (anunciado en 2004) [21] y las construcciones async/await en .NET 4.5 (anunciado en 2010, lanzado en 2012) [22] [23] en gran medida inspirado por los flujos de trabajo asincrónicos de F#, [24] que datan de 2007. [25] Esto ha sido adoptado posteriormente por otros lenguajes, en particular Dart (2014), [26] Python (2015), [27] Hack (HHVM) y borradores de ECMAScript 7 (JavaScript), Scala y C++ (2011).

Lista de implementaciones

Algunos lenguajes de programación admiten futuros, promesas, variables lógicas concurrentes, variables de flujo de datos o I-vars, ya sea mediante soporte directo del lenguaje o en la biblioteca estándar.

Lista de conceptos relacionados con futuros y promesas por lenguaje de programación

Los idiomas que también admiten la canalización de promesas incluyen:

Lista de implementaciones de futuros basadas en bibliotecas

Corrutinas

Los futuros se pueden implementar en corrutinas [27] o generadores [103] , lo que da como resultado la misma estrategia de evaluación (por ejemplo, multitarea cooperativa o evaluación perezosa).

Canales

Los futuros se pueden implementar fácilmente en canales : un futuro es un canal de un elemento y una promesa es un proceso que envía al canal, cumpliendo el futuro. [104] [105] Esto permite que los futuros se implementen en lenguajes de programación concurrentes con soporte para canales, como CSP y Go . Los futuros resultantes son explícitos, ya que se debe acceder a ellos leyendo desde el canal, en lugar de solo evaluarlos.

Véase también

Referencias

  1. ^ Friedman, Daniel; David Wise (1976). El impacto de la programación aplicativa en el multiprocesamiento . Conferencia internacional sobre procesamiento paralelo. págs. 263–272.
    Versión preliminar de: Friedman, Daniel; Wise, David (abril de 1978). "Aspectos de la programación aplicativa para el procesamiento paralelo". IEEE Transactions on Computers . C-27 (4): 289–296. CiteSeerX 10.1.1.295.9692 . doi :10.1109/tc.1978.1675100. S2CID  16333366. 
  2. ^ Hibbard, Peter (1976). Parallel Processing Facilities . Nuevas direcciones en lenguajes algorítmicos, (ed.) Stephen A. Schuman, IRIA, 1976.
  3. ^ Henry Baker; Carl Hewitt (agosto de 1977). The Incremental Garbage Collection of Processes. Actas del Simposio sobre lenguajes de programación de inteligencia artificial. ACM SIGPLAN Notices 12, 8. págs. 55–59. Archivado desde el original el 4 de julio de 2008. Consultado el 13 de febrero de 2015 .
  4. ^ Promesa de canalización en erights.org
  5. ^ Promesa de canalización en la wiki de C2
  6. ^ de Barbara Liskov; Liuba Shrira (1988). "Promises: Linguistic Support for Efficient Asynchronous Procedure Calls in Distributed Systems". Actas de la Conferencia SIGPLAN '88 sobre Diseño e Implementación de Lenguajes de Programación; Atlanta, Georgia, Estados Unidos . ACM. págs. 260–267. doi :10.1145/53990.54016. ISBN . 0-89791-269-1.También publicado en ACM SIGPLAN Notices 23 (7).
  7. ^ Se postergan las promesas sólidas de Dojo, Site Pen, 3 de mayo de 2010
  8. ^ ab "Promise", Alice Manual , DE: Uni-SB, archivado desde el original el 8 de octubre de 2008 , consultado el 21 de marzo de 2007
  9. ^ ab "Future", manual de Alice , DE: Uni-SB, archivado desde el original el 6 de octubre de 2008 , consultado el 21 de marzo de 2007
  10. ^ Promesa, derechos E
  11. ^ 500 líneas o menos, "Un rastreador web con corrutinas asyncio" de A. Jesse Jiryu Davis y Guido van Rossum dice que "la implementación utiliza un asyncio.Event en lugar del Future que se muestra aquí. La diferencia es que un Event se puede restablecer, mientras que un Future no puede pasar de resuelto a pendiente".
  12. ^ Control Concurrent MVar, Haskell, archivado desde el original el 18 de abril de 2009
  13. ^ WaitNeeded, Mozart Oz, archivado desde el original el 17 de mayo de 2013 , consultado el 21 de marzo de 2007
  14. ^ Promesa, Mar sin sol, archivado desde el original el 23 de octubre de 2007
  15. ^ Argus, MIT
  16. ^ Liskov, Barbara (26 de enero de 2021), Computación distribuida y Argus, Historia oral, IEEE GHN
  17. ^ Oro, Udanax, archivado desde el original el 11 de octubre de 2008
  18. ^ Oleoducto, derechos E
  19. ^ Henry Lieberman (junio de 1981). "Un avance del acto 1". MIT AI Memo 625 .
  20. ^ Henry Lieberman (junio de 1981). "Pensar en muchas cosas a la vez sin confundirse: paralelismo en el acto 1". MIT AI Memo 626 .
  21. ^ Goetz, Brian (23 de noviembre de 2004). "Concurrencia en JDK 5.0". IBM .
  22. ^ ab "Async en 4.5: Vale la pena esperar – Blog de .NET – Página principal del sitio – Blogs de MSDN". Blogs.msdn.com . Consultado el 13 de mayo de 2014 .
  23. ^ abc "Programación asincrónica con Async y Await (C# y Visual Basic)". Msdn.microsoft.com . Consultado el 13 de mayo de 2014 .
  24. ^ Tomas Petricek (29 de octubre de 2010). "C# y F# asincrónicos (I.): introducción simultánea".
  25. ^ Don Syme; Tomás Petricek; Dmitry Lomov (21 de octubre de 2010). "El modelo de programación asincrónica de F#, PADL 2011".
  26. ^ ab Gilad Bracha (octubre de 2014). "Soporte de asincronía del lenguaje Dart: fase 1".
  27. ^ ab "PEP 0492 – Corrutinas con sintaxis async y await".
  28. ^ Kenjiro Taura; Satoshi Matsuoka; Akinori Yonezawa (1994). "ABCL/f: Un lenguaje orientado a objetos concurrente, polimórfico y tipado basado en el futuro: su diseño e implementación". En Actas del taller DIMACS sobre especificación de algoritmos paralelos, número 18 en la serie Dimacs en matemáticas discretas y ciencias de la computación teórica . Sociedad Matemática Americana. págs. 275–292. CiteSeerX 10.1.1.23.1161 . 
  29. ^ "Completador asíncrono de dardos SDK de Dart".
  30. ^ "Tarea".
  31. ^ Steve Dekorte (2005). "Io, el lenguaje de programación".
  32. ^ "Uso de promesas". Mozilla Developer Network . Consultado el 23 de febrero de 2021 .
  33. ^ "Hacer que la programación asincrónica sea más sencilla con async y await". Red de desarrolladores de Mozilla . Consultado el 23 de febrero de 2021 .
  34. ^ Rich Hickey (2009). "changes.txt en 1.1.x del clojure de richhickey". GitHub .
  35. ^ "Futuro – Lenguaje de programación Kotlin".
  36. ^ Seif Haridi; Nils Franzen. "Tutorial de Oz". Biblioteca global de usuarios de Mozart. Archivado desde el original el 14 de mayo de 2011. Consultado el 12 de abril de 2011 .
  37. ^ Versión de Python 3.2
  38. ^ Versión de Python 3.5
  39. ^ "Paralelismo con futuros". PLT . Consultado el 2 de marzo de 2012 .
  40. ^ "Promesa de clase". raku.org . Consultado el 19 de agosto de 2022 .
  41. ^ "El futuro en std::future - Rust". doc.rust-lang.org . Consultado el 16 de diciembre de 2023 .
  42. ^ Mirlo común
  43. ^ Common Lisp Eager Future2
  44. ^ Lisp en paralelo: una biblioteca de programación paralela para Common Lisp
  45. ^ PCall de Common Lisp
  46. ^ "Capítulo 30. Hilo 4.0.0" . Consultado el 26 de junio de 2013 .
  47. ^ "Biblioteca Dlib C++ #thread_pool" . Consultado el 26 de junio de 2013 .
  48. ^ "GitHub – facebook/folly: una biblioteca C++ de código abierto desarrollada y utilizada en Facebook". GitHub . 8 de enero de 2019.
  49. ^ "HPX". 10 de febrero de 2019.
  50. ^ "Hilos de diapositivas de POCO" (PDF) .
  51. ^ "QtCore 5.0: Clase QFuture". Proyecto Qt. Archivado desde el original el 1 de junio de 2013. Consultado el 26 de junio de 2013 .
  52. ^ "Estrella de mar". Proyecto Seastar . Consultado el 22 de agosto de 2016 .
  53. ^ "stlab es el trabajo en curso de lo que fue el Laboratorio de Tecnología de Software de Adobe. Las bibliotecas de código fuente de Adobe (ASL), las bibliotecas de plataforma y las nuevas bibliotecas de stlab están alojadas en github". 31 de enero de 2021.
  54. ^ Groovy GPars Archivado el 12 de enero de 2013 en Wayback Machine.
  55. ^ Cujo.js
  56. ^ JavaScript cuando.js
  57. ^ Promesas/Especificación A+
  58. ^ promesas
  59. ^ JavaScript MochKit.Async
  60. ^ JavaScript AngularJS
  61. ^ Nodo de promesa de JavaScript
  62. ^ "JavaScript Q". Archivado desde el original el 31 de diciembre de 2018. Consultado el 8 de abril de 2013 .
  63. ^ JavaScript RSVP.js
  64. ^ Biblioteca de clases de JavaScript de YUI
  65. ^ Clase de promesa de JavaScript de YUI
  66. ^ Pájaro azul de JavaScript
  67. ^ Java JDeferred
  68. ^ Java ParSeq
  69. ^ GitHub de Objective-C MAFuture
  70. ^ Objetivo-C MAFuture mikeash.com
  71. ^ Promesa RX de Objective-C
  72. ^ ObjC-Futuros colapsados
  73. ^ Kit de promesas de Objective-C
  74. ^ Objetivo-C objc-promesa
  75. ^ Promesa OA de Objective-C
  76. ^ OCaml Perezoso
  77. ^ Futuro de Perl
  78. ^ Promesas de Perl
  79. ^ Reflejo de Perl
  80. ^ Promesa de Perl::ES6
  81. ^ "Promise::XS – Promesas rápidas en Perl – metacpan.org". metacpan.org . Consultado el 14 de febrero de 2021 .
  82. ^ PHP React/Promesa
  83. ^ Implementación incorporada de Python
  84. ^ futuros de python
  85. ^ "Twisted Deferreds". Archivado desde el original el 6 de agosto de 2020. Consultado el 29 de abril de 2010 .
  86. ^ Paquete R futuro
  87. ^ futuro
  88. ^ Rubí concurrente
  89. ^ Gema de la promesa de rubí
  90. ^ Rubí libuv
  91. ^ "Gema de celuloide rubí". Archivado desde el original el 8 de mayo de 2013. Consultado el 19 de febrero de 2022 .
  92. ^ Recurso futuro de Ruby
  93. ^ caja futures-rs
  94. ^ Biblioteca de utilidades de Twitter
  95. ^ "Swift Async". Archivado desde el original el 31 de diciembre de 2018. Consultado el 23 de junio de 2014 .
  96. ^ Kit de futuro rápido
  97. ^ MCD de Swift Apple
  98. ^ Libro de futuros rápidos
  99. ^ bignerdranch/Aplazado
  100. ^ Thomvis/BrightFutures
  101. ^ Belozierov/SwiftCoroutine
  102. ^ tcl-promesa
  103. ^ ¿async/await resuelve un problema real?
  104. ^ "Patrones del lenguaje Go Futures". Archivado desde el original el 4 de diciembre de 2020. Consultado el 9 de febrero de 2014 .
  105. ^ "Patrones del lenguaje Go". Archivado desde el original el 11 de noviembre de 2020. Consultado el 9 de febrero de 2014 .

Enlaces externos