SlideShare a Scribd company logo
1 of 73
Download to read offline
LA PROGRAMMATION ASYNCHRONE

ET LES PÂTES

François Zaninotto - @francoisz - marmelab.com
PARLONS

CUISINE
Spaghetti à la tomate de Giuseppina
Plat principal - Facile - Bon marché

Pour 4 personnes
Préparation et cuisson: 20 minutes
Ingrédients:
- 500g de spaghetti
- 6 tomates bien mûres
- 1 oignon
- 1 carotte
- 2 gousses d'ail
- 1 branche de céleri
- huile d'olive
- sauge, romarin, basilic frais
- sel et poivre
- amour
Spaghetti à la tomate de Giuseppina
Plat principal - Facile - Bon marché

1. Faire bouillir une grande quantité d'eau (non salée) dans une casserole
2. Pendant ce temps, pelez les tomates et coupez-les grossièrement
3. Epluchez et émincez l'oignon, la carotte, l'ail et le céleri
4. Lorsque l'eau bout, salez-la, puis déposez les spaghettis en couronne
5. Faire chauffer l'huile d'olive dans une sauteuse. Mettez-y à brunir la deuxième gousse d'ail préalablement épluchée.
6. Retirez la gousse d'ail, puis versez le mirepoix (mélange de légumes) et faites revenir à feu vif
7. Ajoutez les tomates, les herbes, salez et poivrez copieusement. Faites chauffer à feu moyen pendant 5 minutes
8. Goûtez régulièrement les spaghettis. Lorsqu'ils sont cuits al dente, égouttez-les puis déposez-les dans un plat chaud.
9. Versez la sauce tomate immédiatement sur les pâtes fumantes. Ajoutez le basilic grossièrement découpé.
10.Servez avec du parmesan rapé et un bon Chianti Classico, et régalez-vous
MAINTENANT LE CHEF C’EST

PHP
//	
  time	
  is	
  0	
  
$pastaPan	
  =	
  new	
  Pan();	
  
$water	
  =	
  new	
  Water();	
  
$pastaPan-­‐>fill($water);	
  
$pastaPan-­‐>warm($duration	
  =	
  10);	
  
//	
  now	
  time	
  is	
  10	
  
$pastaPan-­‐>fill(new	
  Spaghetti());	
  
$pastaPan-­‐>warm($duration	
  =	
  8);	
  
//	
  now	
  time	
  is	
  18	
  
$pastaPan-­‐>remove($water);	
  
!

$saucePan	
  =	
  new	
  Pan();	
  
$saucePan-­‐>fill(new	
  OliveOil());	
  
$saucePan-­‐>warm($duration	
  =	
  2);	
  
//	
  now	
  time	
  is	
  20	
  
$saucePan-­‐>fill(MirepoixFactory::create($withGarlic	
  =	
  true));	
  
$saucePan-­‐>warm($duration	
  =	
  5);	
  
//	
  now	
  time	
  is	
  25	
  
$saucePan-­‐>fill(TomatoFactory::create());	
  
$saucepan-­‐>warm($duration	
  =	
  4);	
  
//	
  now	
  time	
  is	
  29	
  
!

$plate	
  =	
  new	
  Plate();	
  
$plate-­‐>addContentsOf($pastaPan);	
  
$plate-­‐>addContentsOf($saucePan);	
  
$plate-­‐>serve('Régalez-­‐vous');
LES 3 GRANDS TABOUS
DU DEVELOPPEUR
UTILISER eval()
LES 3 GRANDS TABOUS
DU DEVELOPPEUR
INJECTER UN CONTENEUR
D’INJECTION DE DÉPENDANCE
LES 3 GRANDS TABOUS
DU DEVELOPPEUR

SERVIR DES
PÂTES FROIDES
2/10

NOTE DES INVITÉS
EVENTLOOP
À LA RESCOUSSE
class	
  EventLoop	
  
{	
  
	
  	
  protected	
  $tick	
  =	
  0;	
  
	
  	
  protected	
  $callbacksForTick	
  =	
  array();	
  
!

	
  	
  public	
  function	
  executeLater($delay,	
  $callback)	
  {	
  
	
  	
  	
  	
  $this-­‐>callbacksForTick[$this-­‐>tick	
  +	
  $delay]	
  []=	
  $callback;	
  
	
  	
  }	
  
	
  	
  
	
  	
  public	
  function	
  start()	
  {	
  
	
  	
  	
  	
  while	
  ($this-­‐>callbacksForTick)	
  {	
  
	
  	
  	
  	
  	
  	
  $this-­‐>tick++;	
  
	
  	
  	
  	
  	
  	
  $this-­‐>executeCallbacks();	
  
	
  	
  	
  	
  }	
  
	
  	
  }	
  
	
  	
  	
  
	
  	
  public	
  function	
  executeCallbacks()	
  {	
  
	
  	
  	
  	
  echo	
  "tic-­‐tac	
  :	
  "	
  .	
  $this-­‐>tick	
  .	
  "n";	
  
	
  	
  	
  	
  if	
  (!isset($this-­‐>callbacksForTick[$this-­‐>tick]))	
  {	
  
	
  	
  	
  	
  	
  	
  return;	
  //	
  no	
  callback	
  to	
  execute	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  foreach	
  ($this-­‐>callbacksForTick[$this-­‐>tick]	
  as	
  $callback)	
  {	
  
	
  	
  	
  	
  	
  	
  call_user_func($callback);	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  clean	
  up	
  
	
  	
  	
  	
  unset($this-­‐>callbacksForTick[$this-­‐>tick]);	
  
	
  	
  }	
  
}
LA CASSEROLE

ASYNCHRONE
class	
  AsynchronousPan	
  extends	
  Pan	
  
{	
  
	
  	
  protected	
  $eventLoop;	
  
	
  	
  	
  
	
  	
  public	
  function	
  __construct(EventLoop	
  $eventLoop)	
  
	
  	
  {	
  
	
  	
  	
  	
  $this-­‐>eventLoop	
  =	
  $eventLoop;	
  
	
  	
  }	
  
	
  	
  	
  
	
  	
  public	
  function	
  warm($duration,	
  $callback)	
  
	
  	
  {	
  
	
  	
  	
  	
  $this-­‐>eventLoop-­‐>executeLater($duration,	
  $callback);	
  
	
  	
  }	
  
}
$eventLoop	
  =	
  new	
  EventLoop();	
  
!

$pan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
$pan-­‐>warm(10,	
  function()	
  {	
  
	
  	
  echo	
  "Régalez-­‐vousn";	
  
});	
  
!

echo	
  "Ca	
  chauffe	
  !n";	
  
!

$eventLoop-­‐>start();
DÉMONSTRATION
Ca	
  chauffe	
  !	
  
tic-­‐tac	
  :	
  1	
  
tic-­‐tac	
  :	
  2	
  
tic-­‐tac	
  :	
  3	
  
tic-­‐tac	
  :	
  4	
  
tic-­‐tac	
  :	
  5	
  
tic-­‐tac	
  :	
  6	
  
tic-­‐tac	
  :	
  7	
  
tic-­‐tac	
  :	
  8	
  
tic-­‐tac	
  :	
  9	
  
tic-­‐tac	
  :	
  10	
  
Régalez-­‐vous
LES SPAGHETTI

ASYNCHRONES
$eventLoop	
  =	
  new	
  EventLoop();	
  
!

$plate	
  =	
  new	
  Plate();	
  
!

//	
  pasta	
  
$pastaPan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
$water	
  =	
  new	
  Water();	
  
$pastaPan-­‐>fill($water);	
  
echo	
  "pastaPan:	
  Allumagen";	
  
$pastaPan-­‐>warm($duration	
  =	
  10,	
  function()	
  use	
  ($pastaPan,	
  $plate,	
  $water)	
  {	
  
	
  	
  echo	
  "pastaPan:	
  L'eau	
  boutn";	
  
	
  	
  $pastaPan-­‐>fill(new	
  Spaghetti());	
  
	
  	
  echo	
  "pastaPan:	
  Lancement	
  de	
  la	
  cuisson	
  des	
  spaghettisn";	
  
	
  	
  $pastaPan-­‐>warm($duration	
  =	
  8,	
  function()	
  use	
  ($pastaPan,	
  $plate,	
  $water){	
  
	
  	
  	
  	
  echo	
  "pastaPan:	
  Les	
  spaghettis	
  sont	
  prêtsn";	
  
	
  	
  	
  	
  $pastaPan-­‐>remove($water);	
  
	
  	
  	
  	
  $plate-­‐>addContentsOf($pastaPan);	
  
	
  	
  });	
  
});	
  
../..
../..	
  
//	
  sauce	
  
$eventLoop-­‐>executeLater($delay	
  =	
  7,	
  function()	
  use	
  ($plate,	
  $eventLoop)	
  {	
  
	
  	
  $saucePan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
	
  	
  $saucePan-­‐>fill(new	
  OliveOil());	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  chauffen";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  2,	
  function()	
  use($saucePan,	
  $plate)	
  {	
  
	
  	
  	
  	
  echo	
  "saucePan:	
  L'huile	
  est	
  chauden";	
  
	
  	
  	
  	
  $saucePan-­‐>fill(MirepoixFactory::create($withGarlic	
  =	
  true));	
  
	
  	
  	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  du	
  mirepoixn";	
  
	
  	
  	
  	
  $saucePan-­‐>warm($duration	
  =	
  5,	
  function()	
  use($saucePan,	
  $plate)	
  {	
  
	
  	
  	
  	
  	
  	
  echo	
  "saucePan:	
  Le	
  mirepoix	
  est	
  prêt	
  pour	
  la	
  tomaten";	
  
	
  	
  	
  	
  	
  	
  $saucePan-­‐>fill(TomatoFactory::create());	
  
	
  	
  	
  	
  	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  de	
  la	
  tomaten";	
  
	
  	
  	
  	
  	
  	
  $saucePan-­‐>warm($duration	
  =	
  4,	
  function()	
  use($saucePan,	
  $plate)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  echo	
  "saucePan:	
  La	
  sauce	
  est	
  prêten";	
  
	
  	
  	
  	
  	
  	
  	
  	
  $plate-­‐>addContentsOf($saucePan);	
  
	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  });	
  
	
  	
  });	
  
});	
  
!

$eventLoop-­‐>start();	
  
$plate-­‐>serve('Régalez-­‐vous');
Synchrone

SÉQUENTIALITÉ
Asynchrone
pastaPan:	
  Allumage	
  
tic-­‐tac	
  :	
  1	
  
...	
  
tic-­‐tac	
  :	
  7	
  
saucePan:	
  L'huile	
  chauffe	
  
tic-­‐tac	
  :	
  8	
  
tic-­‐tac	
  :	
  9	
  
saucePan:	
  L'huile	
  est	
  chaude	
  
saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  du	
  mirepoix	
  
tic-­‐tac	
  :	
  10	
  
pastaPan:	
  L'eau	
  bout	
  
pastaPan:	
  Lancement	
  de	
  la	
  cuisson	
  des	
  spaghettis	
  
tic-­‐tac	
  :	
  11	
  
....	
  
tic-­‐tac	
  :	
  14	
  
saucePan:	
  Le	
  mirepoix	
  est	
  prêt	
  pour	
  la	
  tomate	
  
saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  de	
  la	
  tomate	
  
tic-­‐tac	
  :	
  15	
  
...	
  
tic-­‐tac	
  :	
  18	
  
pastaPan:	
  Les	
  spaghettis	
  sont	
  prêts	
  
saucePan:	
  La	
  sauce	
  est	
  prête	
  
Régalez-­‐vous
SCRIPT SYNCHRONE

29 MINUTES
SCRIPT ASYNCHRONE

18 MINUTES
7/10

NOTE DES INVITÉS
class	
  EventLoop	
  
{	
  
	
  	
  protected	
  $tick	
  =	
  0;	
  
	
  	
  protected	
  $callbacksForTick	
  =	
  array();	
  
!

	
  	
  public	
  function	
  executeLater($delay,	
  $callback)	
  {	
  
	
  	
  	
  	
  $this-­‐>callbacksForTick[$this-­‐>tick	
  +	
  $delay]	
  []=	
  $callback;	
  
	
  	
  }	
  
	
  	
  
	
  	
  public	
  function	
  start()	
  {	
  
	
  	
  	
  	
  while	
  ($this-­‐>callbacksForTick)	
  {	
  
	
  	
  	
  	
  	
  	
  $this-­‐>tick++;	
  
	
  	
  	
  	
  	
  	
  $this-­‐>executeCallbacks();	
  
	
  	
  	
  	
  }	
  
	
  	
  }	
  
	
  	
  	
  
	
  	
  public	
  function	
  executeCallbacks()	
  {	
  
	
  	
  	
  	
  echo	
  "tic-­‐tac	
  :	
  "	
  .	
  $this-­‐>tick	
  .	
  "n";	
  
	
  	
  	
  	
  if	
  (!isset($this-­‐>callbacksForTick[$this-­‐>tick]))	
  {	
  
	
  	
  	
  	
  	
  	
  return;	
  //	
  no	
  callback	
  to	
  execute	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  foreach	
  ($this-­‐>callbacksForTick[$this-­‐>tick]	
  as	
  $callback)	
  {	
  
	
  	
  	
  	
  	
  	
  call_user_func($callback);	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  clean	
  up	
  
	
  	
  	
  	
  unset($this-­‐>callbacksForTick[$this-­‐>tick]);	
  
	
  	
  }	
  
}
//	
  ...	
  
$eventLoop-­‐>start();	
  
!

//	
  Never	
  executed	
  
$plate-­‐>serve('Régalez-­‐vous');
RESYNCHRONISER

L’ASYNCHRONE
class	
  PlateOfSpaghettiWithSauce	
  extends	
  Plate	
  
{	
  
	
  	
  protected	
  $hasSpaghetti	
  =	
  false;	
  
	
  	
  protected	
  $hasSauce	
  =	
  false;	
  
	
  	
  	
  
	
  	
  public	
  function	
  addContentsOf(Pan	
  $pan)	
  
	
  	
  {	
  
	
  	
  	
  	
  parent::addContentsOf($pan);	
  
	
  	
  	
  	
  if	
  ($pan-­‐>contains('Spaghetti'))	
  {	
  
	
  	
  	
  	
  	
  	
  $this-­‐>hasSpaghetti	
  =	
  true;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  if	
  ($pan-­‐>contains('Tomato'))	
  {	
  
	
  	
  	
  	
  	
  	
  $this-­‐>hasSauce	
  =	
  true;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  if	
  ($this-­‐>hasSpaghetti	
  &&	
  $this-­‐>hasSauce)	
  {	
  
	
  	
  	
  	
  	
  	
  $this-­‐>serve('Régalez-­‐vous');	
  
	
  	
  	
  	
  }	
  
	
  	
  }	
  
}
../..	
  
//	
  sauce	
  
$eventLoop-­‐>executeLater($delay	
  =	
  7,	
  function()	
  use	
  ($plate,	
  $eventLoop)	
  {	
  
	
  	
  $saucePan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
	
  	
  $saucePan-­‐>fill(new	
  OliveOil());	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  chauffen";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  2,	
  function()	
  use($saucePan,	
  $plate)	
  {	
  
	
  	
  	
  	
  echo	
  "saucePan:	
  L'huile	
  est	
  chauden";	
  
	
  	
  	
  	
  $saucePan-­‐>fill(MirepoixFactory::create($withGarlic	
  =	
  true));	
  
	
  	
  	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  du	
  mirepoixn";	
  
	
  	
  	
  	
  $saucePan-­‐>warm($duration	
  =	
  5,	
  function()	
  use($saucePan,	
  $plate)	
  {	
  
	
  	
  	
  	
  	
  	
  echo	
  "saucePan:	
  Le	
  mirepoix	
  est	
  prêt	
  pour	
  la	
  tomaten";	
  
	
  	
  	
  	
  	
  	
  $saucePan-­‐>fill(TomatoFactory::create());	
  
	
  	
  	
  	
  	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  de	
  la	
  tomaten";	
  
	
  	
  	
  	
  	
  	
  $saucePan-­‐>warm($duration	
  =	
  4,	
  function()	
  use($saucePan,	
  $plate)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  echo	
  "saucePan:	
  La	
  sauce	
  est	
  prêten";	
  
	
  	
  	
  	
  	
  	
  	
  	
  $plate-­‐>addContentsOf($saucePan);	
  
	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  });	
  
	
  	
  });	
  
});	
  
!

$eventLoop-­‐>start();	
  
$plate-­‐>serve('Régalez-­‐vous');
DÉMÊLER
LE CODE
SPAGHETTI
$saucePan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
$eventLoop-­‐>executeLater($delay	
  =	
  7,	
  function()	
  {	
  
	
  	
  call_user_func($warmSaucePan);	
  
});	
  
$warmSaucePan	
  =	
  function()	
  use	
  ($saucePan)	
  {	
  
	
  	
  $saucePan-­‐>fill(new	
  OliveOil());	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  chauffen";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  2,	
  $cookMirepoix);	
  
};	
  
$cookMirepoix	
  =	
  function()	
  use	
  ($saucePan)	
  {	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  est	
  chauden";	
  
	
  	
  $saucePan-­‐>fill(MirepoixFactory::create($withGarlic	
  =	
  true));	
  
	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  du	
  mirepoixn";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  5,	
  $cookTomato);	
  
};	
  
$cookTomato	
  =	
  function()	
  use	
  ($saucePan)	
  {	
  
	
  	
  echo	
  "saucePan:	
  Le	
  mirepoix	
  est	
  prêt	
  pour	
  la	
  tomaten";	
  
	
  	
  $saucePan-­‐>fill(TomatoFactory::create());	
  
	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  de	
  la	
  tomaten";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  4,	
  $serveSauce);	
  
};	
  
$serveSauce	
  =	
  function()	
  use	
  ($saucePan,	
  $plate)	
  {	
  
	
  	
  echo	
  "saucePan:	
  La	
  sauce	
  est	
  prêten";	
  
	
  	
  $plate-­‐>addContentsOf($saucePan);	
  
};
$saucePan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
$serveSauce	
  =	
  function()	
  use	
  ($saucePan,	
  $plate)	
  {	
  
	
  	
  echo	
  "saucePan:	
  La	
  sauce	
  est	
  prêten";	
  
	
  	
  $plate-­‐>addContentsOf($saucePan);	
  
};	
  
$cookTomato	
  =	
  function()	
  use	
  ($saucePan,	
  $serveSauce)	
  {	
  
	
  	
  echo	
  "saucePan:	
  Le	
  mirepoix	
  est	
  prêt	
  pour	
  la	
  tomaten";	
  
	
  	
  $saucePan-­‐>fill(TomatoFactory::create());	
  
	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  de	
  la	
  tomaten";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  4,	
  $serveSauce);	
  
};	
  
$cookMirepoix	
  =	
  function()	
  use	
  ($saucePan,	
  $cookTomato)	
  {	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  est	
  chauden";	
  
	
  	
  $saucePan-­‐>fill(MirepoixFactory::create($withGarlic	
  =	
  true));	
  
	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  du	
  mirepoixn";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  5,	
  $cookTomato);	
  
};	
  
$warmSaucePan	
  =	
  function()	
  use	
  ($saucePan,	
  $cookMirepoix)	
  {	
  
	
  	
  $saucePan-­‐>fill(new	
  OliveOil());	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  chauffen";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  2,	
  $cookMirepoix);	
  
};	
  
$eventLoop-­‐>executeLater($delay	
  =	
  7,	
  function()	
  use	
  ($warmSaucePan)	
  {	
  
	
  	
  	
  	
  call_user_func($warmSaucePan);	
  
});
$saucePan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
$warmSaucePan	
  =	
  function($callback)	
  use	
  ($saucePan)	
  {	
  
	
  	
  $saucePan-­‐>fill(new	
  OliveOil());	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  chauffen";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  2,	
  $callback);	
  
};	
  
$cookMirepoix	
  =	
  function($callback)	
  use	
  ($saucePan)	
  {	
  
	
  	
  echo	
  "saucePan:	
  L'huile	
  est	
  chauden";	
  
	
  	
  $saucePan-­‐>fill(MirepoixFactory::create($withGarlic	
  =	
  true));	
  
	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  du	
  mirepoixn";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  5,	
  $callback);	
  
};	
  
$cookTomato	
  =	
  function($callback)	
  use	
  ($saucePan)	
  {	
  
	
  	
  echo	
  "saucePan:	
  Le	
  mirepoix	
  est	
  prêt	
  pour	
  la	
  tomaten";	
  
	
  	
  $saucePan-­‐>fill(TomatoFactory::create());	
  
	
  	
  echo	
  "saucePan:	
  Lancement	
  de	
  la	
  cuisson	
  de	
  la	
  tomaten";	
  
	
  	
  $saucePan-­‐>warm($duration	
  =	
  4,	
  $callback);	
  
};	
  
$serveSauce	
  =	
  function()	
  use	
  ($saucePan,	
  $plate)	
  {	
  
	
  	
  echo	
  "saucePan:	
  La	
  sauce	
  est	
  prêten";	
  
	
  	
  $plate-­‐>addContentsOf($saucePan);	
  
};	
  
$eventLoop-­‐>executeLater($delay	
  =	
  7,	
  function()	
  use	
  ($plate,	
  $eventLoop)	
  {	
  
	
  	
  Async::waterfall(	
  
	
  	
  	
  	
  array($warmSaucePan,	
  $cookMirepoix,	
  $cookTomato),	
  
	
  	
  	
  	
  $serveSauce	
  
	
  	
  );	
  
});
class	
  Async	
  
{	
  
	
  	
  public	
  static	
  function	
  waterfall($tasks,	
  $callback	
  =	
  null)	
  
	
  	
  {	
  
	
  	
  	
  	
  	
  	
  $taskCallback	
  =	
  function	
  ()	
  use	
  (&$next)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  call_user_func_array($next,	
  func_get_args());	
  
	
  	
  	
  	
  	
  	
  };	
  
	
  	
  	
  	
  	
  	
  $done	
  =	
  function	
  ()	
  use	
  ($callback)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  ($callback)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  call_user_func_array($callback,	
  func_get_args());	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  };	
  
	
  	
  	
  	
  	
  	
  $next	
  =	
  function	
  ()	
  use	
  (&$tasks,	
  $taskCallback,	
  $done)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (0	
  ===	
  count($tasks))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  call_user_func_array($done,	
  func_get_args());	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return;	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
!

	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $task	
  =	
  array_shift($tasks);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $args	
  =	
  array_merge(func_get_args(),	
  array($taskCallback));	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  call_user_func_array($task,	
  $args);	
  
	
  	
  	
  	
  	
  	
  };	
  
	
  	
  	
  	
  	
  	
  $next();	
  
	
  	
  }	
  
}
Source: https://github.com/reactphp/async/blob/master/src/React/Async/Util.php#L81
EN ASYNCHRONE

PAS DE RETURN
//	
  prototype	
  synchronous	
  function	
  
$cook	
  =	
  function($ingredient)	
  use	
  ($saucePan)	
  {	
  
	
  	
  $saucePan-­‐>fill($ingredient);	
  
	
  	
  $saucePan-­‐>warm(5);	
  
	
  	
  return	
  'chaud	
  devant';	
  
};	
  
!
!

$message	
  =	
  $cook(MirepoixFactory::create());	
  
echo	
  $message,	
  "n";	
  
//	
  prototype	
  asynchronous	
  function	
  
$cook	
  =	
  function($ingredient,	
  $callback)	
  use	
  ($saucePan)	
  {	
  
	
  	
  $saucePan-­‐>fill($ingredient);	
  
	
  	
  $saucePan-­‐>warm(5,	
  function()	
  {	
  
	
  	
  	
  	
  $callback('chaud	
  devant');	
  
	
  	
  });	
  
};	
  
!

$cook(MirepoixFactory::create(),	
  function($message)	
  {	
  
	
  	
  echo	
  $message,	
  "n";	
  
});
EN ASYNCHRONE

PAS DE TRY/CATCH
$cook	
  =	
  function($ingredient,	
  $callback)	
  use	
  ($saucePan)	
  {	
  
	
  	
  $saucePan-­‐>fill($ingredient);	
  
	
  	
  $saucePan-­‐>warm(5,	
  function()	
  {	
  
	
  	
  	
  	
  $isSummer	
  =	
  in_array(date('m'),	
  	
  array(6,	
  7,	
  8)):	
  
	
  	
  	
  	
  if	
  ($saucePan-­‐>contains('Tomato')	
  &&	
  !$isSummer)	
  {	
  
	
  	
  	
  	
  	
  	
  throw	
  new	
  OutOfBoundsException('On	
  ne	
  fait	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  de	
  la	
  bonne	
  sauce	
  tomate	
  qu'en	
  été');	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  $callback('chaud	
  devant	
  !');	
  
	
  	
  });	
  
};	
  
!

try	
  {	
  
	
  	
  $cook(MirepoixFactory::create(),	
  function($message)	
  {	
  
	
  	
  	
  	
  echo	
  $message,	
  "n";	
  
	
  	
  });	
  	
  
}	
  catch	
  (OutOfBoundsException	
  $e)	
  {	
  
	
  	
  echo	
  "Echec	
  de	
  la	
  recetten";	
  
}
$cook	
  =	
  function($ingredient,	
  $callback)	
  use	
  ($saucePan)	
  {	
  
	
  	
  $saucePan-­‐>fill($ingredient);	
  
	
  	
  $saucePan-­‐>warm(5,	
  function()	
  {	
  
	
  	
  	
  	
  $isSummer	
  =	
  in_array(date('m'),	
  	
  array(6,	
  7,	
  8)):	
  
	
  	
  	
  	
  if	
  ($saucePan-­‐>contains('Tomato')	
  &&	
  !$isSummer)	
  {	
  
	
  	
  	
  	
  	
  	
  return	
  callback(new	
  OutOfBoundsException('On	
  ne	
  fait	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  de	
  la	
  bonne	
  sauce	
  tomate	
  qu'en	
  ete'));	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  $callback(null,	
  'chaud	
  devant	
  !');	
  
	
  	
  });	
  
};	
  
!

$cook(MirepoixFactory::create(),	
  function($error,	
  $message)	
  {	
  
	
  	
  if	
  ($error	
  instanceOf	
  OutOfBoundsException)	
  {	
  
	
  	
  	
  	
  echo	
  "Echec	
  de	
  la	
  recetten";	
  
	
  	
  	
  	
  return;	
  
	
  	
  }	
  
	
  	
  echo	
  $message,	
  "n";	
  
});
DU CODE

RÉUTILISABLE
ROBUSTE
UN PLAT

CHAUD
VICTOIRE !
10/10
NOTE DES INVITÉS
IL N’Y A TOUJOURS

QU’UN SEUL CHEF
PROGRAMMATION NON

PARALLELE
PAS DE TEMPS PERDU

ARÉPONSE D’UN AUTRE
ATTENDRE
LA
LATENCE I/O
Operation	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  CPU	
  cycles	
  
L1	
  ..................	
  3	
  
L2	
  ..................	
  14	
  
RAM	
  .................	
  250	
  
Disk	
  ................	
  41,000,000	
  
Network	
  .............	
  240,000,000
L1	
  cache	
  reference	
  .........................	
  0.5	
  ns	
  
L2	
  cache	
  reference	
  ...........................	
  7	
  ns	
  
Main	
  memory	
  reference	
  ......................	
  100	
  ns	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
Compress	
  1K	
  bytes	
  with	
  Zippy	
  .............	
  3,000	
  ns	
  	
  =	
  	
  	
  3	
  µs	
  
Send	
  2K	
  bytes	
  over	
  1	
  Gbps	
  network	
  .......	
  20,000	
  ns	
  	
  =	
  	
  20	
  µs	
  
SSD	
  random	
  read	
  ........................	
  150,000	
  ns	
  	
  =	
  150	
  µs	
  
Read	
  1	
  MB	
  sequentially	
  from	
  memory	
  .....	
  250,000	
  ns	
  	
  =	
  250	
  µs	
  
Round	
  trip	
  within	
  same	
  datacenter	
  ......	
  500,000	
  ns	
  	
  =	
  0.5	
  ms	
  
Read	
  1	
  MB	
  sequentially	
  from	
  SSD*	
  .....	
  1,000,000	
  ns	
  	
  =	
  	
  	
  1	
  ms	
  
Disk	
  seek	
  ...........................	
  10,000,000	
  ns	
  	
  =	
  	
  10	
  ms	
  
Read	
  1	
  MB	
  sequentially	
  from	
  disk	
  ....	
  20,000,000	
  ns	
  	
  =	
  	
  20	
  ms	
  
Send	
  packet	
  CA-­‐>Netherlands-­‐>CA	
  ....	
  150,000,000	
  ns	
  	
  =	
  150	
  ms
Source: http://www.cs.cornell.edu/projects/ladis2009/talks/dean-keynote-ladis2009.pdf
I/O = ATTENTE

ETABLISSEMENT CONNEXION SÉCURISÉE
RÉCEPTION REQUÊTE HTTP
REQUÊTE BASE DE DONNÉES
LECTURE VALEUR DANS MEMCACHE
LECTURE DE FICHIER SUR DISQUE
APPEL À UNE API REST
ENVOI MESSAGE À UN AMQP
ENVOI RÉPONSE HTTP
90%

DU TEMPS DE RÉPONSE
D’UNE REQUÊTE HTTP
EST PASSÉ À ATTENDRE UNE I/O
GET	
  /favicon.ico
Process serveur
Routing
Lancement de l’ordre de
chargement du fichier
Déplacement de la tête de lecture
Transfert des données du disque en mémoire
Construction de la réponse HTTP
Traitement
Attente

Envoi de la réponse HTTP
Fin de la requête
UN SERVEUR WEB
PASSE SON TEMPS

A SE TOURNER

LES POUCES
POUR MIEUX UTILISER LE CPU

ON MULTIPLIE

LES PROCESS
LESLA CONSO MÉMOIRE
THREADS
ET DONC
MaxClients	
  50
UN AUTRE MONDE

EST POSSIBLE
GET	
  /favicon.ico
Process serveur
Transfert des données
du disque en mémoire

I/O disque
asynchrone
Envoi de la réponse HTTP

I/O réseau
asynchrone

Traitement
Attente
LIBEL
EVENT LOOP

LIBUV

LIBEIO

ASYNCHRONOUS I/O

MULTI-PLATFORM ABSTRACTION LAYER
GET	
  /favicon.ico
GET	
  /js/jquery.js
GET	
  /css/main.css
COMMENT FAIRE
DES I/O ASYNCHRONES

EN PHP ?
Event-­‐driven,	
  non-­‐blocking	
  I/O	
  with	
  PHP.	
  
PHP & PROCESS PERSISTENTS

PAS BON MÉNAGE
PHP N’A PAS DE FONCTIONS
D’I/O DISQUE ASYNCHRONES
PECL/LIBIO
TANT QU’À INSTALLER
UN BINAIRE
AUTANT EN PRENDRE UN

STABLE
POPULAIRE
TANT QU’À REPOSER
SUR UNE EVENT LOOP
AUTANT UTILISER
UN LANGAGE

ÉVÈNEMENTIEL
TANT QU’À ABUSER
DES FONCTIONS ANONYMES
AUTANT UTILISER UN LANGAGE

FONCTIONNEL
var	
  fs	
  =	
  require('fs');	
  
fs.unlink('/tmp/hello',	
  function	
  (err)	
  {	
  
	
  	
  if	
  (err)	
  throw	
  err;	
  
	
  	
  console.log('successfully	
  deleted	
  /tmp/hello');	
  
});	
  
//	
  more	
  code	
  
console.log('deletion	
  script');
plate	
  =	
  new	
  Plate();	
  
pastaPan	
  =	
  new	
  AsynchronousPan(eventLoop);	
  
water	
  =	
  new	
  Water();	
  
pastaPan.fill(water);	
  
console.log('pastaPan:	
  Starting	
  to	
  boil	
  water');	
  
pastaPan.warm(duration	
  =	
  10,	
  function()	
  {	
  
	
  	
  console.log('pastaPan:	
  Water	
  is	
  boiling');	
  
	
  	
  pastaPan.fill(new	
  Spaghetti());	
  
	
  	
  console.log('pastaPan:	
  Starting	
  to	
  boil	
  spaghetti');	
  
	
  	
  pastaPan.warm(duration	
  =	
  8,	
  function()	
  {	
  
	
  	
  	
  	
  console.log('pastaPan:	
  Spaghetti	
  is	
  ready');	
  
	
  	
  	
  	
  pastaPan.remove(water);	
  
	
  	
  	
  	
  plate.addContentsOf(pastaPan);	
  
	
  	
  });	
  
});
$plate	
  =	
  new	
  Plate();	
  
$pastaPan	
  =	
  new	
  AsynchronousPan($eventLoop);	
  
$water	
  =	
  new	
  Water();	
  
$pastaPan-­‐>fill($water);	
  
echo	
  "pastaPan:	
  Starting	
  to	
  boil	
  watern";	
  
$pastaPan-­‐>warm($duration	
  =	
  10,	
  function()	
  use	
  ($pastaPan,	
  $plate,	
  $water)	
  {	
  
	
  	
  echo	
  "pastaPan:	
  Water	
  is	
  boilingn";	
  
	
  	
  $pastaPan-­‐>fill(new	
  Spaghetti());	
  
	
  	
  echo	
  "pastaPan:	
  Starting	
  to	
  boil	
  spaghettin";	
  
	
  	
  $pastaPan-­‐>warm($duration	
  =	
  8,	
  function()	
  use	
  ($pastaPan,	
  $plate,	
  $water)	
  {	
  
	
  	
  	
  	
  echo	
  "pastaPan:	
  Spaghetti	
  is	
  readyn";	
  
	
  	
  	
  	
  $pastaPan-­‐>remove($water);	
  
	
  	
  	
  	
  $plate-­‐>addContentsOf($pastaPan);	
  
	
  	
  });	
  
});
I/O ASYNCHRONES

UN SEUL CHEF
DES CALLBACKS
PLUS DE CONCURRENCE
MOINS DE CONSOL MÉMOIRE
PAS POSSIBLE EN PHP, NATIF EN NODE.JS
PAS DE RETURN, PAS DE TRY/CATCH
DES PÂTES

CHAUDES
MERCI
François Zaninotto - @francoisz - marmelab.com
github.com/fzaninotto - github.com/marmelab

More Related Content

Similar to La programmation asynchrone... et les pates

TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012Amazon Web Services
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
Writing Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::CmdWriting Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::CmdRicardo Signes
 
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014Amazon Web Services
 
Functional Groovy
Functional GroovyFunctional Groovy
Functional Groovynoamt
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type Systemabrummett
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...Mateusz Zalewski
 
Feature Flags Are Flawed: Let's Make Them Better
Feature Flags Are Flawed: Let's Make Them BetterFeature Flags Are Flawed: Let's Make Them Better
Feature Flags Are Flawed: Let's Make Them BetterStephen Young
 
The Art of Transduction
The Art of TransductionThe Art of Transduction
The Art of TransductionDavid Stockton
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16Ricardo Signes
 

Similar to La programmation asynchrone... et les pates (11)

TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
TLS305 Using DynamoDB with the AWS SDK for PHP - AWS re: Invent 2012
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
Writing Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::CmdWriting Modular Command-line Apps with App::Cmd
Writing Modular Command-line Apps with App::Cmd
 
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
(DEV305) Building Apps with the AWS SDK for PHP | AWS re:Invent 2014
 
Functional Groovy
Functional GroovyFunctional Groovy
Functional Groovy
 
The Perl6 Type System
The Perl6 Type SystemThe Perl6 Type System
The Perl6 Type System
 
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
[PHPCon 2023] “Kto to pisał?!... a, to ja.”, czyli sposoby żeby znienawidzić ...
 
Jasmine
JasmineJasmine
Jasmine
 
Feature Flags Are Flawed: Let's Make Them Better
Feature Flags Are Flawed: Let's Make Them BetterFeature Flags Are Flawed: Let's Make Them Better
Feature Flags Are Flawed: Let's Make Them Better
 
The Art of Transduction
The Art of TransductionThe Art of Transduction
The Art of Transduction
 
What's New in Perl? v5.10 - v5.16
What's New in Perl?  v5.10 - v5.16What's New in Perl?  v5.10 - v5.16
What's New in Perl? v5.10 - v5.16
 

More from Francois Zaninotto

Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !Francois Zaninotto
 
Le jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du webLe jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du webFrancois Zaninotto
 
Frameworks : A history of violence
Frameworks : A history of violenceFrameworks : A history of violence
Frameworks : A history of violenceFrancois Zaninotto
 
La migration continue vers Symfony
La migration continue vers SymfonyLa migration continue vers Symfony
La migration continue vers SymfonyFrancois Zaninotto
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfonyFrancois Zaninotto
 

More from Francois Zaninotto (10)

Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !Vous aimez les legos ? React est fait pour vous !
Vous aimez les legos ? React est fait pour vous !
 
GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?
 
Le jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du webLe jeu vidéo à la rescousse du web
Le jeu vidéo à la rescousse du web
 
Frameworks : A history of violence
Frameworks : A history of violenceFrameworks : A history of violence
Frameworks : A history of violence
 
Php 100k
Php 100kPhp 100k
Php 100k
 
La migration continue vers Symfony
La migration continue vers SymfonyLa migration continue vers Symfony
La migration continue vers Symfony
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Symfony2 meets propel 1.5
Symfony2 meets propel 1.5Symfony2 meets propel 1.5
Symfony2 meets propel 1.5
 
Developing for Developers
Developing for DevelopersDeveloping for Developers
Developing for Developers
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
 

Recently uploaded

Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 

Recently uploaded (20)

Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 

La programmation asynchrone... et les pates

  • 1. LA PROGRAMMATION ASYNCHRONE ET LES PÂTES François Zaninotto - @francoisz - marmelab.com
  • 3. Spaghetti à la tomate de Giuseppina Plat principal - Facile - Bon marché Pour 4 personnes Préparation et cuisson: 20 minutes Ingrédients: - 500g de spaghetti - 6 tomates bien mûres - 1 oignon - 1 carotte - 2 gousses d'ail - 1 branche de céleri - huile d'olive - sauge, romarin, basilic frais - sel et poivre - amour
  • 4. Spaghetti à la tomate de Giuseppina Plat principal - Facile - Bon marché 1. Faire bouillir une grande quantité d'eau (non salée) dans une casserole 2. Pendant ce temps, pelez les tomates et coupez-les grossièrement 3. Epluchez et émincez l'oignon, la carotte, l'ail et le céleri 4. Lorsque l'eau bout, salez-la, puis déposez les spaghettis en couronne 5. Faire chauffer l'huile d'olive dans une sauteuse. Mettez-y à brunir la deuxième gousse d'ail préalablement épluchée. 6. Retirez la gousse d'ail, puis versez le mirepoix (mélange de légumes) et faites revenir à feu vif 7. Ajoutez les tomates, les herbes, salez et poivrez copieusement. Faites chauffer à feu moyen pendant 5 minutes 8. Goûtez régulièrement les spaghettis. Lorsqu'ils sont cuits al dente, égouttez-les puis déposez-les dans un plat chaud. 9. Versez la sauce tomate immédiatement sur les pâtes fumantes. Ajoutez le basilic grossièrement découpé. 10.Servez avec du parmesan rapé et un bon Chianti Classico, et régalez-vous
  • 5. MAINTENANT LE CHEF C’EST PHP
  • 6. //  time  is  0   $pastaPan  =  new  Pan();   $water  =  new  Water();   $pastaPan-­‐>fill($water);   $pastaPan-­‐>warm($duration  =  10);   //  now  time  is  10   $pastaPan-­‐>fill(new  Spaghetti());   $pastaPan-­‐>warm($duration  =  8);   //  now  time  is  18   $pastaPan-­‐>remove($water);   ! $saucePan  =  new  Pan();   $saucePan-­‐>fill(new  OliveOil());   $saucePan-­‐>warm($duration  =  2);   //  now  time  is  20   $saucePan-­‐>fill(MirepoixFactory::create($withGarlic  =  true));   $saucePan-­‐>warm($duration  =  5);   //  now  time  is  25   $saucePan-­‐>fill(TomatoFactory::create());   $saucepan-­‐>warm($duration  =  4);   //  now  time  is  29   ! $plate  =  new  Plate();   $plate-­‐>addContentsOf($pastaPan);   $plate-­‐>addContentsOf($saucePan);   $plate-­‐>serve('Régalez-­‐vous');
  • 7. LES 3 GRANDS TABOUS DU DEVELOPPEUR UTILISER eval()
  • 8. LES 3 GRANDS TABOUS DU DEVELOPPEUR INJECTER UN CONTENEUR D’INJECTION DE DÉPENDANCE
  • 9. LES 3 GRANDS TABOUS DU DEVELOPPEUR SERVIR DES PÂTES FROIDES
  • 12. class  EventLoop   {      protected  $tick  =  0;      protected  $callbacksForTick  =  array();   !    public  function  executeLater($delay,  $callback)  {          $this-­‐>callbacksForTick[$this-­‐>tick  +  $delay]  []=  $callback;      }          public  function  start()  {          while  ($this-­‐>callbacksForTick)  {              $this-­‐>tick++;              $this-­‐>executeCallbacks();          }      }            public  function  executeCallbacks()  {          echo  "tic-­‐tac  :  "  .  $this-­‐>tick  .  "n";          if  (!isset($this-­‐>callbacksForTick[$this-­‐>tick]))  {              return;  //  no  callback  to  execute          }          foreach  ($this-­‐>callbacksForTick[$this-­‐>tick]  as  $callback)  {              call_user_func($callback);          }          //  clean  up          unset($this-­‐>callbacksForTick[$this-­‐>tick]);      }   }
  • 14. class  AsynchronousPan  extends  Pan   {      protected  $eventLoop;            public  function  __construct(EventLoop  $eventLoop)      {          $this-­‐>eventLoop  =  $eventLoop;      }            public  function  warm($duration,  $callback)      {          $this-­‐>eventLoop-­‐>executeLater($duration,  $callback);      }   }
  • 15. $eventLoop  =  new  EventLoop();   ! $pan  =  new  AsynchronousPan($eventLoop);   $pan-­‐>warm(10,  function()  {      echo  "Régalez-­‐vousn";   });   ! echo  "Ca  chauffe  !n";   ! $eventLoop-­‐>start();
  • 17. Ca  chauffe  !   tic-­‐tac  :  1   tic-­‐tac  :  2   tic-­‐tac  :  3   tic-­‐tac  :  4   tic-­‐tac  :  5   tic-­‐tac  :  6   tic-­‐tac  :  7   tic-­‐tac  :  8   tic-­‐tac  :  9   tic-­‐tac  :  10   Régalez-­‐vous
  • 19. $eventLoop  =  new  EventLoop();   ! $plate  =  new  Plate();   ! //  pasta   $pastaPan  =  new  AsynchronousPan($eventLoop);   $water  =  new  Water();   $pastaPan-­‐>fill($water);   echo  "pastaPan:  Allumagen";   $pastaPan-­‐>warm($duration  =  10,  function()  use  ($pastaPan,  $plate,  $water)  {      echo  "pastaPan:  L'eau  boutn";      $pastaPan-­‐>fill(new  Spaghetti());      echo  "pastaPan:  Lancement  de  la  cuisson  des  spaghettisn";      $pastaPan-­‐>warm($duration  =  8,  function()  use  ($pastaPan,  $plate,  $water){          echo  "pastaPan:  Les  spaghettis  sont  prêtsn";          $pastaPan-­‐>remove($water);          $plate-­‐>addContentsOf($pastaPan);      });   });   ../..
  • 20. ../..   //  sauce   $eventLoop-­‐>executeLater($delay  =  7,  function()  use  ($plate,  $eventLoop)  {      $saucePan  =  new  AsynchronousPan($eventLoop);      $saucePan-­‐>fill(new  OliveOil());      echo  "saucePan:  L'huile  chauffen";      $saucePan-­‐>warm($duration  =  2,  function()  use($saucePan,  $plate)  {          echo  "saucePan:  L'huile  est  chauden";          $saucePan-­‐>fill(MirepoixFactory::create($withGarlic  =  true));          echo  "saucePan:  Lancement  de  la  cuisson  du  mirepoixn";          $saucePan-­‐>warm($duration  =  5,  function()  use($saucePan,  $plate)  {              echo  "saucePan:  Le  mirepoix  est  prêt  pour  la  tomaten";              $saucePan-­‐>fill(TomatoFactory::create());              echo  "saucePan:  Lancement  de  la  cuisson  de  la  tomaten";              $saucePan-­‐>warm($duration  =  4,  function()  use($saucePan,  $plate)  {                  echo  "saucePan:  La  sauce  est  prêten";                  $plate-­‐>addContentsOf($saucePan);              });          });      });   });   ! $eventLoop-­‐>start();   $plate-­‐>serve('Régalez-­‐vous');
  • 22. pastaPan:  Allumage   tic-­‐tac  :  1   ...   tic-­‐tac  :  7   saucePan:  L'huile  chauffe   tic-­‐tac  :  8   tic-­‐tac  :  9   saucePan:  L'huile  est  chaude   saucePan:  Lancement  de  la  cuisson  du  mirepoix   tic-­‐tac  :  10   pastaPan:  L'eau  bout   pastaPan:  Lancement  de  la  cuisson  des  spaghettis   tic-­‐tac  :  11   ....   tic-­‐tac  :  14   saucePan:  Le  mirepoix  est  prêt  pour  la  tomate   saucePan:  Lancement  de  la  cuisson  de  la  tomate   tic-­‐tac  :  15   ...   tic-­‐tac  :  18   pastaPan:  Les  spaghettis  sont  prêts   saucePan:  La  sauce  est  prête   Régalez-­‐vous
  • 26. class  EventLoop   {      protected  $tick  =  0;      protected  $callbacksForTick  =  array();   !    public  function  executeLater($delay,  $callback)  {          $this-­‐>callbacksForTick[$this-­‐>tick  +  $delay]  []=  $callback;      }          public  function  start()  {          while  ($this-­‐>callbacksForTick)  {              $this-­‐>tick++;              $this-­‐>executeCallbacks();          }      }            public  function  executeCallbacks()  {          echo  "tic-­‐tac  :  "  .  $this-­‐>tick  .  "n";          if  (!isset($this-­‐>callbacksForTick[$this-­‐>tick]))  {              return;  //  no  callback  to  execute          }          foreach  ($this-­‐>callbacksForTick[$this-­‐>tick]  as  $callback)  {              call_user_func($callback);          }          //  clean  up          unset($this-­‐>callbacksForTick[$this-­‐>tick]);      }   }
  • 27. //  ...   $eventLoop-­‐>start();   ! //  Never  executed   $plate-­‐>serve('Régalez-­‐vous');
  • 29. class  PlateOfSpaghettiWithSauce  extends  Plate   {      protected  $hasSpaghetti  =  false;      protected  $hasSauce  =  false;            public  function  addContentsOf(Pan  $pan)      {          parent::addContentsOf($pan);          if  ($pan-­‐>contains('Spaghetti'))  {              $this-­‐>hasSpaghetti  =  true;          }          if  ($pan-­‐>contains('Tomato'))  {              $this-­‐>hasSauce  =  true;          }          if  ($this-­‐>hasSpaghetti  &&  $this-­‐>hasSauce)  {              $this-­‐>serve('Régalez-­‐vous');          }      }   }
  • 30. ../..   //  sauce   $eventLoop-­‐>executeLater($delay  =  7,  function()  use  ($plate,  $eventLoop)  {      $saucePan  =  new  AsynchronousPan($eventLoop);      $saucePan-­‐>fill(new  OliveOil());      echo  "saucePan:  L'huile  chauffen";      $saucePan-­‐>warm($duration  =  2,  function()  use($saucePan,  $plate)  {          echo  "saucePan:  L'huile  est  chauden";          $saucePan-­‐>fill(MirepoixFactory::create($withGarlic  =  true));          echo  "saucePan:  Lancement  de  la  cuisson  du  mirepoixn";          $saucePan-­‐>warm($duration  =  5,  function()  use($saucePan,  $plate)  {              echo  "saucePan:  Le  mirepoix  est  prêt  pour  la  tomaten";              $saucePan-­‐>fill(TomatoFactory::create());              echo  "saucePan:  Lancement  de  la  cuisson  de  la  tomaten";              $saucePan-­‐>warm($duration  =  4,  function()  use($saucePan,  $plate)  {                  echo  "saucePan:  La  sauce  est  prêten";                  $plate-­‐>addContentsOf($saucePan);              });          });      });   });   ! $eventLoop-­‐>start();   $plate-­‐>serve('Régalez-­‐vous');
  • 32. $saucePan  =  new  AsynchronousPan($eventLoop);   $eventLoop-­‐>executeLater($delay  =  7,  function()  {      call_user_func($warmSaucePan);   });   $warmSaucePan  =  function()  use  ($saucePan)  {      $saucePan-­‐>fill(new  OliveOil());      echo  "saucePan:  L'huile  chauffen";      $saucePan-­‐>warm($duration  =  2,  $cookMirepoix);   };   $cookMirepoix  =  function()  use  ($saucePan)  {      echo  "saucePan:  L'huile  est  chauden";      $saucePan-­‐>fill(MirepoixFactory::create($withGarlic  =  true));      echo  "saucePan:  Lancement  de  la  cuisson  du  mirepoixn";      $saucePan-­‐>warm($duration  =  5,  $cookTomato);   };   $cookTomato  =  function()  use  ($saucePan)  {      echo  "saucePan:  Le  mirepoix  est  prêt  pour  la  tomaten";      $saucePan-­‐>fill(TomatoFactory::create());      echo  "saucePan:  Lancement  de  la  cuisson  de  la  tomaten";      $saucePan-­‐>warm($duration  =  4,  $serveSauce);   };   $serveSauce  =  function()  use  ($saucePan,  $plate)  {      echo  "saucePan:  La  sauce  est  prêten";      $plate-­‐>addContentsOf($saucePan);   };
  • 33. $saucePan  =  new  AsynchronousPan($eventLoop);   $serveSauce  =  function()  use  ($saucePan,  $plate)  {      echo  "saucePan:  La  sauce  est  prêten";      $plate-­‐>addContentsOf($saucePan);   };   $cookTomato  =  function()  use  ($saucePan,  $serveSauce)  {      echo  "saucePan:  Le  mirepoix  est  prêt  pour  la  tomaten";      $saucePan-­‐>fill(TomatoFactory::create());      echo  "saucePan:  Lancement  de  la  cuisson  de  la  tomaten";      $saucePan-­‐>warm($duration  =  4,  $serveSauce);   };   $cookMirepoix  =  function()  use  ($saucePan,  $cookTomato)  {      echo  "saucePan:  L'huile  est  chauden";      $saucePan-­‐>fill(MirepoixFactory::create($withGarlic  =  true));      echo  "saucePan:  Lancement  de  la  cuisson  du  mirepoixn";      $saucePan-­‐>warm($duration  =  5,  $cookTomato);   };   $warmSaucePan  =  function()  use  ($saucePan,  $cookMirepoix)  {      $saucePan-­‐>fill(new  OliveOil());      echo  "saucePan:  L'huile  chauffen";      $saucePan-­‐>warm($duration  =  2,  $cookMirepoix);   };   $eventLoop-­‐>executeLater($delay  =  7,  function()  use  ($warmSaucePan)  {          call_user_func($warmSaucePan);   });
  • 34. $saucePan  =  new  AsynchronousPan($eventLoop);   $warmSaucePan  =  function($callback)  use  ($saucePan)  {      $saucePan-­‐>fill(new  OliveOil());      echo  "saucePan:  L'huile  chauffen";      $saucePan-­‐>warm($duration  =  2,  $callback);   };   $cookMirepoix  =  function($callback)  use  ($saucePan)  {      echo  "saucePan:  L'huile  est  chauden";      $saucePan-­‐>fill(MirepoixFactory::create($withGarlic  =  true));      echo  "saucePan:  Lancement  de  la  cuisson  du  mirepoixn";      $saucePan-­‐>warm($duration  =  5,  $callback);   };   $cookTomato  =  function($callback)  use  ($saucePan)  {      echo  "saucePan:  Le  mirepoix  est  prêt  pour  la  tomaten";      $saucePan-­‐>fill(TomatoFactory::create());      echo  "saucePan:  Lancement  de  la  cuisson  de  la  tomaten";      $saucePan-­‐>warm($duration  =  4,  $callback);   };   $serveSauce  =  function()  use  ($saucePan,  $plate)  {      echo  "saucePan:  La  sauce  est  prêten";      $plate-­‐>addContentsOf($saucePan);   };   $eventLoop-­‐>executeLater($delay  =  7,  function()  use  ($plate,  $eventLoop)  {      Async::waterfall(          array($warmSaucePan,  $cookMirepoix,  $cookTomato),          $serveSauce      );   });
  • 35. class  Async   {      public  static  function  waterfall($tasks,  $callback  =  null)      {              $taskCallback  =  function  ()  use  (&$next)  {                      call_user_func_array($next,  func_get_args());              };              $done  =  function  ()  use  ($callback)  {                      if  ($callback)  {                              call_user_func_array($callback,  func_get_args());                      }              };              $next  =  function  ()  use  (&$tasks,  $taskCallback,  $done)  {                      if  (0  ===  count($tasks))  {                              call_user_func_array($done,  func_get_args());                              return;                      }   !                    $task  =  array_shift($tasks);                      $args  =  array_merge(func_get_args(),  array($taskCallback));                      call_user_func_array($task,  $args);              };              $next();      }   } Source: https://github.com/reactphp/async/blob/master/src/React/Async/Util.php#L81
  • 37. //  prototype  synchronous  function   $cook  =  function($ingredient)  use  ($saucePan)  {      $saucePan-­‐>fill($ingredient);      $saucePan-­‐>warm(5);      return  'chaud  devant';   };   ! ! $message  =  $cook(MirepoixFactory::create());   echo  $message,  "n";  
  • 38. //  prototype  asynchronous  function   $cook  =  function($ingredient,  $callback)  use  ($saucePan)  {      $saucePan-­‐>fill($ingredient);      $saucePan-­‐>warm(5,  function()  {          $callback('chaud  devant');      });   };   ! $cook(MirepoixFactory::create(),  function($message)  {      echo  $message,  "n";   });
  • 39. EN ASYNCHRONE PAS DE TRY/CATCH
  • 40. $cook  =  function($ingredient,  $callback)  use  ($saucePan)  {      $saucePan-­‐>fill($ingredient);      $saucePan-­‐>warm(5,  function()  {          $isSummer  =  in_array(date('m'),    array(6,  7,  8)):          if  ($saucePan-­‐>contains('Tomato')  &&  !$isSummer)  {              throw  new  OutOfBoundsException('On  ne  fait                    de  la  bonne  sauce  tomate  qu'en  été');          }          $callback('chaud  devant  !');      });   };   ! try  {      $cook(MirepoixFactory::create(),  function($message)  {          echo  $message,  "n";      });     }  catch  (OutOfBoundsException  $e)  {      echo  "Echec  de  la  recetten";   }
  • 41. $cook  =  function($ingredient,  $callback)  use  ($saucePan)  {      $saucePan-­‐>fill($ingredient);      $saucePan-­‐>warm(5,  function()  {          $isSummer  =  in_array(date('m'),    array(6,  7,  8)):          if  ($saucePan-­‐>contains('Tomato')  &&  !$isSummer)  {              return  callback(new  OutOfBoundsException('On  ne  fait                    de  la  bonne  sauce  tomate  qu'en  ete'));          }          $callback(null,  'chaud  devant  !');      });   };   ! $cook(MirepoixFactory::create(),  function($error,  $message)  {      if  ($error  instanceOf  OutOfBoundsException)  {          echo  "Echec  de  la  recetten";          return;      }      echo  $message,  "n";   });
  • 45. IL N’Y A TOUJOURS QU’UN SEUL CHEF
  • 47. PAS DE TEMPS PERDU ARÉPONSE D’UN AUTRE ATTENDRE LA
  • 48. LATENCE I/O Operation                          CPU  cycles   L1  ..................  3   L2  ..................  14   RAM  .................  250   Disk  ................  41,000,000   Network  .............  240,000,000
  • 49. L1  cache  reference  .........................  0.5  ns   L2  cache  reference  ...........................  7  ns   Main  memory  reference  ......................  100  ns                           Compress  1K  bytes  with  Zippy  .............  3,000  ns    =      3  µs   Send  2K  bytes  over  1  Gbps  network  .......  20,000  ns    =    20  µs   SSD  random  read  ........................  150,000  ns    =  150  µs   Read  1  MB  sequentially  from  memory  .....  250,000  ns    =  250  µs   Round  trip  within  same  datacenter  ......  500,000  ns    =  0.5  ms   Read  1  MB  sequentially  from  SSD*  .....  1,000,000  ns    =      1  ms   Disk  seek  ...........................  10,000,000  ns    =    10  ms   Read  1  MB  sequentially  from  disk  ....  20,000,000  ns    =    20  ms   Send  packet  CA-­‐>Netherlands-­‐>CA  ....  150,000,000  ns    =  150  ms Source: http://www.cs.cornell.edu/projects/ladis2009/talks/dean-keynote-ladis2009.pdf
  • 50. I/O = ATTENTE ETABLISSEMENT CONNEXION SÉCURISÉE RÉCEPTION REQUÊTE HTTP REQUÊTE BASE DE DONNÉES LECTURE VALEUR DANS MEMCACHE LECTURE DE FICHIER SUR DISQUE APPEL À UNE API REST ENVOI MESSAGE À UN AMQP ENVOI RÉPONSE HTTP
  • 51. 90% DU TEMPS DE RÉPONSE D’UNE REQUÊTE HTTP EST PASSÉ À ATTENDRE UNE I/O
  • 52. GET  /favicon.ico Process serveur Routing Lancement de l’ordre de chargement du fichier Déplacement de la tête de lecture Transfert des données du disque en mémoire Construction de la réponse HTTP Traitement Attente Envoi de la réponse HTTP Fin de la requête
  • 53. UN SERVEUR WEB PASSE SON TEMPS A SE TOURNER LES POUCES
  • 54. POUR MIEUX UTILISER LE CPU ON MULTIPLIE LES PROCESS LESLA CONSO MÉMOIRE THREADS ET DONC
  • 56. UN AUTRE MONDE EST POSSIBLE
  • 57. GET  /favicon.ico Process serveur Transfert des données du disque en mémoire I/O disque asynchrone Envoi de la réponse HTTP I/O réseau asynchrone Traitement Attente
  • 60. COMMENT FAIRE DES I/O ASYNCHRONES EN PHP ?
  • 62. PHP & PROCESS PERSISTENTS PAS BON MÉNAGE
  • 63. PHP N’A PAS DE FONCTIONS D’I/O DISQUE ASYNCHRONES PECL/LIBIO
  • 64. TANT QU’À INSTALLER UN BINAIRE AUTANT EN PRENDRE UN STABLE POPULAIRE
  • 65. TANT QU’À REPOSER SUR UNE EVENT LOOP AUTANT UTILISER UN LANGAGE ÉVÈNEMENTIEL
  • 66. TANT QU’À ABUSER DES FONCTIONS ANONYMES AUTANT UTILISER UN LANGAGE FONCTIONNEL
  • 67.
  • 68. var  fs  =  require('fs');   fs.unlink('/tmp/hello',  function  (err)  {      if  (err)  throw  err;      console.log('successfully  deleted  /tmp/hello');   });   //  more  code   console.log('deletion  script');
  • 69. plate  =  new  Plate();   pastaPan  =  new  AsynchronousPan(eventLoop);   water  =  new  Water();   pastaPan.fill(water);   console.log('pastaPan:  Starting  to  boil  water');   pastaPan.warm(duration  =  10,  function()  {      console.log('pastaPan:  Water  is  boiling');      pastaPan.fill(new  Spaghetti());      console.log('pastaPan:  Starting  to  boil  spaghetti');      pastaPan.warm(duration  =  8,  function()  {          console.log('pastaPan:  Spaghetti  is  ready');          pastaPan.remove(water);          plate.addContentsOf(pastaPan);      });   });
  • 70. $plate  =  new  Plate();   $pastaPan  =  new  AsynchronousPan($eventLoop);   $water  =  new  Water();   $pastaPan-­‐>fill($water);   echo  "pastaPan:  Starting  to  boil  watern";   $pastaPan-­‐>warm($duration  =  10,  function()  use  ($pastaPan,  $plate,  $water)  {      echo  "pastaPan:  Water  is  boilingn";      $pastaPan-­‐>fill(new  Spaghetti());      echo  "pastaPan:  Starting  to  boil  spaghettin";      $pastaPan-­‐>warm($duration  =  8,  function()  use  ($pastaPan,  $plate,  $water)  {          echo  "pastaPan:  Spaghetti  is  readyn";          $pastaPan-­‐>remove($water);          $plate-­‐>addContentsOf($pastaPan);      });   });
  • 71. I/O ASYNCHRONES UN SEUL CHEF DES CALLBACKS PLUS DE CONCURRENCE MOINS DE CONSOL MÉMOIRE PAS POSSIBLE EN PHP, NATIF EN NODE.JS PAS DE RETURN, PAS DE TRY/CATCH
  • 73. MERCI François Zaninotto - @francoisz - marmelab.com github.com/fzaninotto - github.com/marmelab