asynchrone y attendre sont des sucres syntaxiques. L'essence de async et await est la machine à états. Le compilateur transformera votre code async/await en une machine à états.
En même temps, pour qu'async/await soit réellement applicable dans des projets réels, nous devons avoir beaucoup de Fonctions de la bibliothèque d'E/S asynchrones déjà en place. En C#, la plupart des fonctions d'E/S synchronisées originales ont une version alternative Async. La raison pour laquelle nous avons besoin de ces fonctions Async est que, dans la plupart des cas, votre propre code async/await se résumera à une méthode Async de la bibliothèque.
La version asynchrone des fonctions de la bibliothèque en C# est un peu comme le concept de canal asynchrone en Java. Par exemple, nous avons AsynchronousFileChannel.read qui peut soit retourner un Future, soit exécuter une callback une fois l'opération de lecture terminée. Mais ce n'est pas exactement la même chose. Toutes les fonctions asynchrones C# renvoient des Tasks (similaires à Future mais plus puissants que Future).
Supposons que Java supporte l'asynchronisme et l'attente, et que nous écrivions un code comme celui-ci :
public static async Future<Byte> readFirstByteAsync(String filePath) {
Path path = Paths.get(filePath);
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(100_000);
await channel.read(buffer, 0, buffer, this);
return buffer.get(0);
}
J'imagine alors que le compilateur transformera le code original async/await en quelque chose comme ceci :
public static Future<Byte> readFirstByteAsync(String filePath) {
CompletableFuture<Byte> result = new CompletableFuture<Byte>();
AsyncHandler ah = new AsyncHandler(result, filePath);
ah.completed(null, null);
return result;
}
Et voici l'implémentation pour AsyncHandler :
class AsyncHandler implements CompletionHandler<Integer, ByteBuffer>
{
CompletableFuture<Byte> future;
int state;
String filePath;
public AsyncHandler(CompletableFuture<Byte> future, String filePath)
{
this.future = future;
this.state = 0;
this.filePath = filePath;
}
@Override
public void completed(Integer arg0, ByteBuffer arg1) {
try {
if (state == 0) {
state = 1;
Path path = Paths.get(filePath);
AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);
ByteBuffer buffer = ByteBuffer.allocate(100_000);
channel.read(buffer, 0, buffer, this);
return;
} else {
Byte ret = arg1.get(0);
future.complete(ret);
}
} catch (Exception e) {
future.completeExceptionally(e);
}
}
@Override
public void failed(Throwable arg0, ByteBuffer arg1) {
future.completeExceptionally(arg0);
}
}