Je suis assez nouveau dans les coroutines, donc je voulais demander un avis.
J'ai créé une fonction d'extension pour lire les données du InputStream
:
suspend fun InputStream.readData(): ByteArray { return withContext(Dispatchers.IO) { while (available() == 0) { delay(10) } val count = available() val buffer = ByteArray(count) read(buffer, 0, count) return@withContext buffer } }
Pensez-vous qu'il y a quelque chose que je pourrais améliorer du point de vue des coroutines?
3 Réponses :
Votre code semble correct du point de vue des coroutines, rien à améliorer. Appelez simplement la fonction depuis un constructeur de coroutine: lancez - si vous voulez une concurrence ou async - si vous voulez le parallélisme. Par exemple:
suspend fun InputStream.readData(): ByteArray = withContext(Dispatchers.IO) { while (available() == 0) { delay(10) } val count = available() val buffer = ByteArray(count) read(buffer, 0, count) buffer }
De plus, vous pouvez réduire un peu votre code en remplaçant return @ withContext buffer
par buffer
et en déplaçant parContext (Dispatchers.IO)
hors du bloc de la fonction:
yourScope.launch { val inputStream = BufferedInputStream(FileInputStream("filename")) val result = inputStream.use { it.readData() } // use ByteArray result }
while (available() == 0) { delay(10) } Here you hope you've achieved non-blocking IO using the InputStream. You imagine that the data would be somehow "trickling in" on its own and you could just wait for it to become available so you can pick it up without blocking in the subsequent read() call.This behavior isn't universal to any InputStream. In fact, it probably only works with a SocketInputStream and there it also has issues: when the remote end has closed the connection, it will keep returning 0 until you make another read call to observe that the socket is closed.In other implementations of InputStream, available() will always return 0 unless the stream is buffered, in which case it will simply tell you how much is left in the buffer. When the buffer is empty, the input stream implementation won't try to fetch any more data from the underlying resource until you call read().Therefore I'd suggest at least narrowing down the receiver of your function to SocketInputStream, but for full correctness you should use NIO code instead.Finally, if you find that for your specific use case the available() loop does work as expected and read() never blocks, then you should drop withContext(IO) because it is implies two costly context switches (to a background thread and back) and its purpose is only to run blocking code off the GUI thread.
Le code que j'ai posté est pour lire à partir d'une prise. Le problème avec l'opération read () est qu'elle bloque et ne peut pas être annulée. Je vais utiliser le code publié à l'intérieur de la clause withTimeout
, c'est donc la raison du delay (10)
.
Pour autant que je sache, le mécanisme available ()
est inutile dans tous les cas. Cela n'a jamais fonctionné pour moi et je l'ai essayé plusieurs fois. Vous devez utiliser des E / S réseau non bloquantes et exécuter dans le répartiteur Main
.
Je pense que tout dépend de la façon dont on veut utiliser le inputStream
. Dans mon cas, je vais lire jusqu'à ce que je trouve les informations qui m'intéressent (ou la lecture expirera). Ne lit pas tant que le socket n'est pas fermé. De plus, selon la documentation, le available ()
renvoie le numéro qui ne bloquera pas l'opération de lecture.
En plus de la réponse de Marko, j'aimerais souligner que le fait que vous ne puissiez pas transformer votre code de blocage en code non bloquant simplement en utilisant des coroutines ne signifie pas que vous ne devriez pas utiliser de coroutines. Il est logique de les utiliser pour obtenir d’autres avantages:
J'espère que cela vous aidera à comprendre la situation dans son ensemble.