Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala中的并行文件处理_Scala_Akka_Actor - Fatal编程技术网

Scala中的并行文件处理

Scala中的并行文件处理,scala,akka,actor,Scala,Akka,Actor,假设我需要并行处理给定文件夹中的文件。在Java中,我将创建一个FolderReader线程,从文件夹和FileProcessor线程池中读取文件名FolderReader读取文件名并将文件处理功能(Runnable)提交给池执行器 在Scala中,我看到两个选项: 创建一个FileProcessor参与者池,并使用actors.Scheduler计划文件处理功能 读取文件名时,为每个文件名创建一个参与者 这有意义吗?最好的选择是什么?理想情况下,您应该使用两个参与者。一个用于读取文件列表,

假设我需要并行处理给定文件夹中的文件。在Java中,我将创建一个
FolderReader
线程,从文件夹和
FileProcessor
线程池中读取文件名
FolderReader
读取文件名并将文件处理功能(
Runnable
)提交给池执行器

在Scala中,我看到两个选项:

  • 创建一个
    FileProcessor
    参与者池,并使用
    actors.Scheduler
    计划文件处理功能
  • 读取文件名时,为每个文件名创建一个参与者

这有意义吗?最好的选择是什么?

理想情况下,您应该使用两个参与者。一个用于读取文件列表,另一个用于实际读取文件

您只需向第一个参与者发送一条“开始”消息即可开始该过程。然后,参与者可以读取文件列表,并向第二个参与者发送消息。然后,第二个参与者读取文件并处理内容

有多个参与者,这可能看起来很复杂,实际上是一件好事,因为你有一堆对象彼此通信,就像在一个理论上的OO系统中一样


编辑:你真的不应该同时读取一个文件。

我建议尽我所能远离线程。幸运的是,我们有更好的抽象来处理下面发生的事情,在你的例子中,我觉得你不需要使用演员(虽然你可以),但是你可以使用一个更简单的抽象,叫做未来。它们是Akka开源库的一部分,我认为将来也将是Scala标准库的一部分

未来[T]只是在未来返回T的东西。

运行future所需要的只是一个隐式的ExecutionContext,您可以从java executor服务派生它。然后,您将能够享受优雅的API以及future是将集合转换为futures集合、收集结果等的monad这一事实。我建议你去看看

这里发生了很多事情:

  • 我使用的是
    Future.transverse
    ,它作为第一个参数接收
    M[T]Future[T]
    或者如果您喜欢
    函数1[T,Future[T]
    并返回Future[M[T]]
  • 我正在使用
    Future.apply
    方法创建一个类型为
    Future[T]
还有许多其他的理由来看待阿克卡期货

  • 可以映射期货,因为它们是单子,也就是说,可以链接期货执行:

    Future{3}.map{{u*2}.map{{{uu.toString}

  • 期货有回调:future.onComplete、onSuccess、onFailure等等

  • 期货不仅支持遍历,也支持理解


我本打算写下@Edmondo1984所做的一切,但他却抢先告诉了我。:)我非常赞同他的建议。我还建议您阅读相关文档。另外,我会给你一个更具体的例子:

import akka.dispatch.{ExecutionContext, Future, Await}
import akka.util.duration._
import java.util.concurrent.Executors
import java.io.File

val execService = Executors.newCachedThreadPool()
implicit val execContext = ExecutionContext.fromExecutorService(execService)

val tmp = new File("/tmp/")
val files = tmp.listFiles()
val workers = files.map { f =>
  Future {
    f.getAbsolutePath()
  }
}.toSeq
val result = Future.sequence(workers)
result.onSuccess {
  case filenames =>
    filenames.foreach { fn =>
      println(fn)
    }
}

// Artificial just to make things work for the example
Thread.sleep(100)
execContext.shutdown()
在这里,我使用了
序列
而不是
遍历
,但区别将取决于您的需要

与未来同行,我的朋友;在这种情况下,演员只是一种更痛苦的方法



取决于你在做什么,它可能很简单

for(file<-files.par){
   //process the file
}

for(file好吧,抓起你的文件,把它们放在一个平行的结构中

scala> new java.io.File("/tmp").listFiles.par
res0: scala.collection.parallel.mutable.ParArray[java.io.File] = ParArray( ... )
然后

scala> res0 map (_.length)
res1: scala.collection.parallel.mutable.ParArray[Long] = ParArray(4943, 1960, 4208, 103266, 363 ... )

但是如果使用演员,那有什么错呢

如果我们必须读/写某个属性文件,这是我的Java示例,但仍然使用Akka Actors

假设我们有一个actor
ActorFile
代表一个文件。嗯……可能它不能代表一个文件。对吗?(如果可以的话)那么它代表几个文件,比如
PropertyFilesActor
,然后:

为什么不使用这样的东西:

public class PropertyFilesActor extends UntypedActor {

    Map<String, String> filesContent = new LinkedHashMap<String, String>();

    { // here we should use real files of cource
        filesContent.put("file1.xml", "");
        filesContent.put("file2.xml", "");
    }

    @Override
    public void onReceive(Object message) throws Exception {

        if (message instanceof WriteMessage)  {
            WriteMessage writeMessage = (WriteMessage) message;
            String content = filesContent.get(writeMessage.fileName);
            String newContent = content + writeMessage.stringToWrite;
            filesContent.put(writeMessage.fileName, newContent);
        }

        else if (message instanceof ReadMessage) {
            ReadMessage readMessage = (ReadMessage) message;
            String currentContent = filesContent.get(readMessage.fileName);
            // Send the current content back to the sender
            getSender().tell(new ReadMessage(readMessage.fileName, currentContent), getSelf());
        }

        else unhandled(message);

    }

}
公共类PropertyFilesActor扩展了UntypedActor{
Map filesContent=新建LinkedHashMap();
{//这里我们应该使用真实的cource文件
filecontent.put(“file1.xml”,“”);
filecontent.put(“file2.xml”,”);
}
@凌驾
public void onReceive(对象消息)引发异常{
if(WriteMessage的消息实例){
WriteMessage WriteMessage=(WriteMessage)消息;
String content=filecontent.get(writeMessage.fileName);
String newContent=content+writeMessage.stringToWrite;
filecontent.put(writeMessage.fileName,newContent);
}
else if(ReadMessage的消息实例){
ReadMessage ReadMessage=(ReadMessage)消息;
字符串currentContent=filesContent.get(readMessage.fileName);
//将当前内容发送回发件人
getSender().tell(新的ReadMessage(ReadMessage.fileName,currentContent),getSelf());
}
否则未处理(消息);
}
}
…消息将与参数(文件名)一起出现

它在框中有自己的
,接受如下消息:

  • WriteLine(文件名、字符串)
  • ReadLine(文件名、字符串)
  • 这些消息将按顺序一个接一个地存储到
    收件箱中。参与者将通过接收收件箱中的消息来完成其工作-存储/读取,同时将反馈发送回
    发件人!消息


    因此,假设我们写入属性文件,并在网页上显示内容。我们可以开始显示页面(在发送消息将数据存储到文件之后),并且在收到反馈后,立即使用刚刚更新的文件中的数据更新部分页面(通过ajax).

    并发硬盘访问不好。它会导致额外的磁头移动。不要这样做。在这里使用Actors是错误的。@DanielC.Sobral谢谢。您能解释一下为什么
    public class PropertyFilesActor extends UntypedActor {
    
        Map<String, String> filesContent = new LinkedHashMap<String, String>();
    
        { // here we should use real files of cource
            filesContent.put("file1.xml", "");
            filesContent.put("file2.xml", "");
        }
    
        @Override
        public void onReceive(Object message) throws Exception {
    
            if (message instanceof WriteMessage)  {
                WriteMessage writeMessage = (WriteMessage) message;
                String content = filesContent.get(writeMessage.fileName);
                String newContent = content + writeMessage.stringToWrite;
                filesContent.put(writeMessage.fileName, newContent);
            }
    
            else if (message instanceof ReadMessage) {
                ReadMessage readMessage = (ReadMessage) message;
                String currentContent = filesContent.get(readMessage.fileName);
                // Send the current content back to the sender
                getSender().tell(new ReadMessage(readMessage.fileName, currentContent), getSelf());
            }
    
            else unhandled(message);
    
        }
    
    }