3

J'ai une méthode simple qui écrit une ligne de données dans un fichier suivi d'une nouvelle ligne qui est exécutée de manière asynchrone. Lorsque mon programme s'exécute, j'obtiens des lignes "mélangées" dans le fichier en raison de la nature asynchrone des appels. Par exemple ... dire writeToFile (pc, "toto") est exécuté 3 fois de manière asynchrone j'obtenir:Quelle est la meilleure façon d'utiliser les threads Scala pour écrire dans un BufferedWriter?

sortie correcte

foo

foo

foo

sortie incorrecte possible

foofoo

foo

Je suis en mesure d'éviter cette possibilité en utilisant synchronisée méthode comme ceci:

def writeToFile(bw: BufferedWriter, str: String) = synchronized { 
    bw.write(str) 
    bw.newLine 
    } 

D'après ce que je fait des recherches je ne peux pas déterminer à quel point cela est "sûr" en ce qui concerne la mise à l'échelle de mon application. Les seuls exemples que je peux trouver en utilisant synchronisé est lors de l'accès aux collections, ne pas écrire dans un fichier. Mon application est construite dans le jeu! Cadre 2.4.2.

+2

Vous avez raison, synchronisé est le moyen conçu par JVM pour verrouiller cet appel de fonction. Toutefois, cela ne signifie pas que BufferedWriter que vous avez passé est protégé pendant ce temps si d'autres threads tentent de l'utiliser, il peut donc être judicieux d'envelopper et de masquer cet objet. Référence ce lien pour plus d'informations: https://twitter.github.io/scala_school/concurrency.html – LaloInDublin

Répondre

7

Personnellement, je créerais un acteur akka pour chaque BufferedWriter ce qui l'encapsulera complètement.

import java.io.BufferedWriter 
import akka.actor._ 
import playground.BufferedWriterActor.WriteToBuffer 

object BufferedWriterActor { 
    val name = "BufferedWriterActor" 
    def props(bw: BufferedWriter) = Props(classOf[BufferedWriterActor], bw) 

    case class WriteToBuffer(str: String) 
} 

class BufferedWriterActor(bw: BufferedWriter) extends Actor { 

    def receive: Actor.Receive = { 
    case WriteToBuffer(str) => 
     bw.write(str) 
     bw.newLine() 
    } 
} 

utiliser comme ceci:

import akka.actor.{ActorSystem, Props} 

object HelloWorld { 
    def main(args: Array[String]): Unit = { 
    val system = ActorSystem("mySystem") 

    // Share this actor across all your threads. 
    val myActor = system.actorOf(BufferedWriterActor.props(bw), BufferedWriterActor.name) 

    // Send messages to this actor from all you threads. 
    myActor ! BufferedWriterActor.WriteToBuffer("The Text") 
    } 
} 

Cette chaîne volonté tous les appels vers ce tampon dans un seul fil.

Plus d'informations sur Akka et ses acteurs est ici:

http://akka.io/

http://doc.akka.io/docs/akka/snapshot/scala/actors.html

jouent également cadre lui-même utilise akka donc vous devriez être en mesure d'utiliser sa valeur par défaut ActorSystem, mais je ne me souviens pas comment exactement, désolé.