Tietojenkäsittelytieteessä konstruktit ja joissakin ohjelmointikielissä muodostavat rinnakkaislaskennan arviointistrategian . _ Heidän avullaan kuvataan kohde, johon voi päästä käsiksi tulokseen, jonka laskentaa ei ehkä ole vielä valmis. futurepromisedelay
Termin lupaus keksivät vuonna 1976 Daniel Friedman ja David Wise [1], ja Peter Hibbard kutsui sitä mahdolliseksi . [2] Henry Bakerin ja Carl Hewittin vuoden 1977 artikkelissa ehdotettiin samanlaista tulevaisuutta kutsuvaa konseptia . [3]
Termejä tulevaisuus , lupaus ja viive käytetään melko usein keskenään, mutta tulevaisuuden ja lupauksen välinen ero kuvataan alla . Future on yleensä vain luku -muotoinen esitys muuttujasta, kun taas lupaus on muuttuva yhden määrityksen säilö , joka välittää tulevaisuuden arvon . [4] Tulevaisuus voidaan määritellä määrittelemättä, mistä lupauksesta arvo tulee. Myös useita lupauksia voidaan liittää yhteen tulevaisuuteen , mutta vain yksi lupaus voi antaa arvon tulevaisuudelle. Muuten tulevaisuus ja lupaus luodaan yhdessä ja sidotaan toisiinsa: tulevaisuus on arvo ja lupaus on funktio, joka antaa arvon. Käytännössä tulevaisuus on asynkronisen lupausfunktion palautusarvo . Tulevaisuuden arvon määrittämistä kutsutaan ratkaisemiseksi , täyttämiseksi tai sitomiseksi .
Jotkut venäjänkieliset lähteet käyttävät seuraavia termien käännöksiä: for future - future results [5] , futures [6] [7] [8] ; lupaukselle lupaus [9] [5] ; viivästymisestä — viive.
On huomattava, että lukemattomilla (" tulevaisuus ") ja kaksisanaisilla (" tulevaisuuden arvo ") käännöksillä on hyvin rajallinen käyttökelpoisuus (katso keskustelu ). Erityisesti Alice ML -kieli tarjoaa futuresensiluokkaisia ominaisuuksia, mukaan lukien futures ensimmäisen luokan ML-moduulit - future modulesja future type modules[10] - ja kaikkia näitä termejä ei voida kääntää näitä muunnelmia käytettäessä. Termin mahdollinen käännös tässä tapauksessa osoittautuu " tulevaiseksi " - vastaavasti antamalla joukon termejä " ensiluokan futuurit ", " moduulitason futuurit ", " tulevaisuusrakenteet " ja " tulevaisuuden allekirjoitukset ". Ilmainen käännös " perspektiivistä " on mahdollista vastaavalla terminologialla.
Tulevaisuuden käyttö voi olla implisiittistä (jokainen viittaus tulevaisuuteen palauttaa viittauksen arvoon) tai eksplisiittinen (käyttäjän on kutsuttava funktio saadakseen arvon). Esimerkki on Java- kielen luokan get -metodi . Arvon saamista eksplisiittisestä tulevaisuudesta kutsutaan pistelyksi tai pakottamiseksi . Eksplisiittiset futuurit voidaan toteuttaa kirjastona, kun taas implisiittiset futuurit toteutetaan yleensä osana kieltä. java.util.concurrent.Future
Bakerin ja Hewittin artikkelissa kuvataan implisiittisiä futuureja, joita luonnollisesti tuetaan toimijan laskentamallissa ja puhtaasti oliokielissä , kuten Smalltalk . Friedmanin ja Wisen artikkelissa kuvataan vain eksplisiittisiä futuureja, mikä johtuu todennäköisesti implisiittisten futuurien toteuttamisen vaikeuksista perinteisissä tietokoneissa. Vaikeus on siinä, että laitteistotasolla tulevaisuuden kanssa ei voida työskennellä primitiivisenä tietotyyppinä, kuten kokonaislukuina. Esimerkiksi append-käskyä käyttämällä ei voida käsitellä 3 + tulevaa factorial(100000) . Puhtaasti objektikielillä ja toimijamallia tukevilla kielillä tämä ongelma voidaan ratkaista lähettämällä tulevaisuuden faktoriaali(100000) +[3] -viesti , jossa tulevaisuutta kehotetaan lisäämään 3 ja palauttamaan tulos. On syytä huomata, että viestin välitysmenetelmä toimii riippumatta siitä, kuinka kauan faktoriaalin (100000) laskeminen kestää, eikä se vaadi pistelyä tai pakottamista.
Tulevaisuutta käytettäessä hajautettujen järjestelmien viiveet vähenevät merkittävästi . Esimerkiksi futuurien avulla voit luoda putkilinjan lupauksesta [11] [12] , joka on toteutettu kielillä, kuten E ja Joule , sekä Argusissa nimeltä call-stream .
Harkitse lauseketta käyttämällä perinteisiä etäproseduurikutsuja :
t3 := ( xa() ).c( yb() )joka voidaan paljastaa
t1 := xa(); t2 := yb(); t3:= t1.c(t2);Jokaisessa lausunnossa sinun on ensin lähetettävä viesti ja saatava siihen vastaus ennen kuin jatkat seuraavaan. Oletetaan, että x , y , t1 ja t2 ovat samassa etäkoneessa. Tässä tapauksessa kolmannen väitteen suorittamiseksi sinun on ensin suoritettava kaksi tiedonsiirtoa verkon yli. Sitten kolmas käsky suorittaa toisen tiedonsiirron samalle etäkoneelle.
Tämä lauseke voidaan kirjoittaa uudelleen käyttämällä tulevaisuutta
t3 := (x <- a()) <- c(y <- b())ja julkistetaan nimellä
t1 := x <- a(); t2 := y <- b(); t3:= t1 <- c(t2);Tämä käyttää syntaksia E-kielestä, jossa x <- a() tarkoittaa "asynkronisesti välittää viesti a() x :ään ". Kaikista kolmesta muuttujasta tulee tulevaisuutta, ja ohjelman suoritus jatkuu. Myöhemmin, kun yritetään saada t3 :n arvoa , saattaa ilmetä viive; putkilinjan käyttö voi kuitenkin vähentää tätä. Jos, kuten edellisessä esimerkissä, x , y , t1 ja t2 sijaitsevat samassa etäkoneessa, niin t3 :n laskenta on mahdollista toteuttaa liukuhihnalla ja yhdellä verkon yli tapahtuvalla tiedonsiirrolla. Koska kaikki kolme viestiä koskevat muuttujia, jotka sijaitsevat samassa etäkoneessa, sinun tarvitsee suorittaa vain yksi pyyntö ja saada yksi vastaus saadaksesi tuloksen. Huomaa, että siirto t1 <- c(t2) ei estä, vaikka t1 ja t2 olisivat eri koneissa toisistaan tai x :stä ja y :stä .
Liukulinjan käyttö lupauksesta tulee erottaa viestin välittämisestä rinnakkain asynkronisesti. Järjestelmissä, jotka tukevat rinnakkaista viestinvälitystä, mutta eivät tue liukuhihnaa, esimerkin sanomien x <- a() ja y <- b() lähettäminen voidaan tehdä rinnakkain, mutta t1 <- c(t2) on lähetettävä odota kunnes t1 vastaanotetaan ja t2 , vaikka x , y , t1 ja t2 olisivat samassa etäkoneessa. Liukuhihnan käytön viiveetu tulee merkittävämmäksi monimutkaisissa tilanteissa, joissa on lähetettävä useita viestejä.
On tärkeää olla sekoittamatta lupausputkea viestiputkeen toimijajärjestelmissä , joissa toimijan on mahdollista määrittää ja aloittaa seuraavan viestin käyttäytyminen ennen kuin edellinen on käsitellyt.
Joissakin ohjelmointikielissä, kuten Oz , E ja AmbientTalk , on mahdollista saada muuttumaton esitys tulevaisuudesta, jonka avulla voit saada sen arvon ratkaisun jälkeen, mutta joka ei salli sinun ratkaista:
Muuttumattomien esitysten tuki on sopusoinnussa vähimmän etuoikeuden periaatteen kanssa , koska pääsy arvoon voidaan myöntää vain niille objekteille, jotka sitä tarvitsevat. Liukuputkia tukevissa järjestelmissä asynkronisen viestin (tuloksen kanssa) lähettäjä saa muuttumattoman lupauksen tuloksesta ja viestin vastaanottaja on ratkaiseja.
Joillakin kielillä, kuten Alice ML , futuurit on sidottu tiettyyn säikeeseen, joka arvioi arvon. Arviointi voi alkaa heti, kun tulevaisuus on luotu, tai laiskasti , eli tarpeen mukaan. "Laska" tulevaisuus on kuin tukala (laiska arvioinnin kannalta).
Alice ML tukee myös futuureja, jotka voidaan ratkaista millä tahansa säikeellä, ja sitä kutsutaan siellä myös lupaukseksi . [14] On syytä huomata, että tässä yhteydessä lupaus ei tarkoita samaa kuin yllä oleva E-esimerkki : Liisan lupaus ei ole muuttumaton esitys, eikä Liisa tue lupausten täyttämistä. Mutta putkistot toimivat luonnollisesti futuurien kanssa (mukaan lukien lupauksiin sidotut).
Jos tulevaan arvoon päästään asynkronisesti, esimerkiksi välittämällä sille viesti tai odottamalla whenE:n konstruktia, ei ole vaikeaa odottaa tulevaisuuden ratkaisemista ennen viestin vastaanottamista. Tämä on ainoa asia, joka on otettava huomioon puhtaasti asynkronisissa järjestelmissä, kuten kielissä, joissa on näyttelijämalli.
Joissakin järjestelmissä on kuitenkin mahdollista päästä tulevaan arvoon välittömästi ja synkronisesti . Tämä voidaan saavuttaa seuraavilla tavoilla:
Ensimmäinen tapa on toteutettu esimerkiksi C++11 :ssä, jossa säie, josta haluat saada tulevan arvon, voi tukkeutua, kunnes jäsen toimii wait()tai get(). Voit määrittää aikakatkaisun ikuisen eston välttämiseksi käyttämällä wait_for()tai -näppäintä. wait_until()Jos tulevaisuus saadaan suorituksen tuloksena std::async, niin odotussäikeen estävällä odotuksella (ei aikakatkaisua) funktion suorittamisen tulos voidaan vastaanottaa synkronisesti.
I-muuttuja ( Id -kielellä ) on tulevaisuus, jossa on yllä kuvattu estosemantiikka. I-rakenne on tietorakenne, joka koostuu I-muuttujista. Samanlaista synkronointiin käytettävää rakennetta, jossa arvo voidaan antaa useita kertoja, kutsutaan M-muuttujaksi . M-muuttujat tukevat atomioperaatioita muuttujan arvon saamiseksi ja kirjoittamiseksi, jolloin arvon saaminen palauttaa M-muuttujan tyhjään tilaan. [17]
Rinnakkainen looginen muuttuja on samanlainen kuin tulevaisuus, mutta päivitetään yhdistämisen aikana samalla tavalla kuin logiikkaohjelmoinnin loogiset muuttujat . Siksi se voidaan liittää useampaan kuin yhteen yhtenäiseen arvoon (mutta ei voi palata tyhjään tai ratkaisemattomaan tilaan). Säikeen muuttujat Ozissa toimivat kuten samanaikaiset Boolen muuttujat yllä kuvatun estosemantiikan kanssa.
Rajoitettu rinnakkaismuuttuja on rinnakkaisten loogisten muuttujien yleistys, joka tukee rajoitettua logiikkaa ohjelmointia : rajoitus voi kaventaa sallittujen arvojen joukkoa useita kertoja. Yleensä on olemassa tapa määrittää thunk, joka suoritetaan jokaisessa kavennuksessa; tämä on tarpeen rajoitteen leviämisen tukemiseksi .
Voimakkaasti lasketut säiekohtaiset futuurit voidaan toteuttaa suoraan ei-säiekohtaisina futuureina luomalla säie, joka arvioi arvoa tulevaisuuden luomishetkellä. Tässä tapauksessa on toivottavaa palauttaa asiakkaalle vain luku -näkymä, jotta vain luotu säie voi suorittaa tulevaisuuden.
Implisiittisten laiska lankakohtaisten futuurien toteuttaminen (kuten Alice ML:ssä) ei-säiekohtaisten futuurien suhteen vaatii mekanismin, joka määrittää tulevaisuuden arvon ensimmäisen käyttökohdan (kuten WaitNeeded- konstrukti Ozissa [18] ). Jos kaikki arvot ovat objekteja, arvon välittämiseksi riittää läpinäkyvien objektien toteuttaminen, koska ensimmäinen viesti edelleenlähettävälle objektille osoittaa, että tulevaisuuden arvo on arvioitava.
Ei-säiekohtaisia futuureja voidaan toteuttaa säiekohtaisten futuurien kautta, jos järjestelmä tukee viestien välitystä. Tulevaisuuden arvoa vaativa säie voi lähettää viestin tulevaan säikeeseen. Tämä lähestymistapa aiheuttaa kuitenkin ylimääräisen monimutkaisuuden. Säikepohjaisissa ohjelmointikielissä ilmeisin lähestymistapa on luultavasti yhdistelmä ei-säiekohtaisia futuureja, vain luku -näkymiä ja joko "WaitNeeded"-rakennetta tai läpinäkyvän edelleenlähetyksen tukea.
" Call by future " -arviointistrategia on epädeterministinen : tulevaisuuden arvo arvioidaan jossain vaiheessa luomisen jälkeen, mutta ennen käyttöä. Arviointi voi alkaa heti tulevaisuuden luomisen jälkeen (" innokas arviointi ") tai vain sillä hetkellä, kun arvoa tarvitaan ( laiska arviointi , viivästynyt arviointi). Kun tulevaisuuden tulos on arvioitu, myöhempiä kutsuja ei lasketa uudelleen. Siten tulevaisuus tarjoaa sekä puhelun tarpeen mukaan että muistiinpanon .
Laiska tulevaisuus -konsepti tarjoaa deterministisen laiskan arvioinnin semantiikan: tulevaisuuden arvon arviointi alkaa arvon ensimmäisestä käyttökerrasta, kuten "call by tarve" -menetelmässä. Laiskot futuurit ovat hyödyllisiä ohjelmointikielissä, jotka eivät tarjoa laiskoja arvioita. Esimerkiksi C++11 :ssä samanlainen rakennelma voidaan luoda määrittämällä käynnistyskäytäntö std::launch::syncja std::asyncvälittämällä funktiolle, joka arvioi arvon.
Toimijamallissa muodon lauseke ''future'' <Expression>määritellään vastaukseksi Eval -viestiin ympäristössä E kuluttajalle C : Tuleva lauseke vastaa Eval -viestiin lähettämällä kuluttajalle C juuri luodun toimijan F (välityspalvelin vastaus <Expression>arvolla ) palautusarvona, samalla kun lähetetään lauseke Eval<Expression> viestit ympäristössä E kuluttajalle C . F : n käyttäytyminen määritellään seuraavasti:
Jotkut tulevaisuuden toteutukset voivat käsitellä pyyntöjä eri tavalla rinnakkaisuuden asteen lisäämiseksi. Esimerkiksi lauseke 1 + tulevaisuustekijä(n) voi luoda uuden tulevaisuuden, joka käyttäytyy kuten luku 1+factorial(n) .
Tulevaisuus - ja lupausrakenteet toteutettiin ensin MultiLisp - ja Act 1 - ohjelmointikielillä . Boolean -muuttujien käyttö vuorovaikutuksessa samanaikaisissa logiikkaohjelmointikielissä on melko samanlaista kuin tulevaisuudessa. Niiden joukossa ovat Prolog with Freeze ja IC Prolog , täysimittaisen kilpailukykyisen primitiivin ovat toteuttaneet Relational Language , Concurrent Prolog , Guarded Horn Clauses (GHC), Parlog , Strand , Vulcan , Janus , Mozart / Oz , Flow Java ja Alice ML . Yksittäiset I-var- määritykset tietovuon ohjelmointikielistä , jotka otettiin alun perin käyttöön Id :ssä ja sisältyivät Reppy Concurrent ML :ään , ovat samanlaisia kuin samanaikaiset loogiset muuttujat.
Barbara Liskov ja Liuba Shrira ehdottivat lupausputkitekniikkaa , joka käyttää futuureja viivästysten voittamiseksi, vuonna 1988 [19] ja itsenäisesti Mark S. Miller , Dean Tribble ja Rob Jellinghaus osana Project Xanadua noin vuonna 1989 [20] .
Liskov ja Shrira keksivät sanan lupaus , vaikka he kutsuivatkin putkimekanismia kutsuvirtaukseksi (nyt käytetään harvoin).
Molemmissa teoksissa ja Xanadun lupausputken toteutuksessa lupaukset eivät olleet ensiluokkaisia objekteja : funktion argumentit ja palautusarvot eivät voineet olla lupauksia suoraan (mikä vaikeuttaa liukuhihnan toteuttamista esimerkiksi Xanadussa). lupausta ja puheluvirtaa ei toteutettu Argusin [21] julkisissa versioissa (Liskovin ja Shriran työssä käytetty ohjelmointikieli); Argus lopetti kehityksen vuonna 1988. [22] Putkilinjan toteutus Xanadussa tuli saataville vasta, kun Udanax Gold [23] julkaistiin vuonna 1999, eikä sitä selitetä julkaistuissa asiakirjoissa. [24]
Joulen ja E:n lupaustoteutukset tukevat niitä ensiluokkaisina objekteina.
Useat varhaiset Actor-kielet, mukaan lukien Act-kielet, [25] [26] tukivat rinnakkaista viestien välitystä ja viestien liukuhihnaa, mutta eivät lupausputkia. (Huolimatta mahdollisuudesta toteuttaa lupausputki tuettujen konstruktien kautta, ei ole todisteita sellaisista toteutuksista Act-kielillä.)
Tulevaisuuden käsite voidaan toteuttaa kanavien suhteen : tulevaisuus on yksittäinen kanava ja lupaus on prosessi, joka lähettää arvon kanavalle suorittamalla tulevaisuuden [27] . Näin futuurit toteutetaan samanaikaisilla kanavaa tukevilla kielillä, kuten CSP ja Go . Niiden toteuttamat futuurit ovat eksplisiittisiä, koska niihin päästään lukemalla kanavasta, ei normaalin lausekkeen arvioinnin avulla.