文件和网络I / O操作的并行化

时间:2013-06-19 09:24:18

标签: java multithreading parallel-processing data-synchronization

问题:

  • 主要问题:平行这些工作的最佳策略是什么?
  • 想法:如何使用其他机制加速进程,例如第二个校验和(Adler32?)

Szenario:

我在java中编写了一种同步工具。基本上,它从Web服务器下载存储库,该服务器表示本地计算机上的文件/目录结构,并以压缩形式定义所需文件的源,并结合哈希值来验证文件。我猜是一个基本的东西。

要求:

  • 多平台Java桌面应用程序
  • 最佳速度和并行化

示例结构:(最好使用游戏模式描述)

示例存储库文件

{"name":"subset1", "mods":[
    {
        "modfolder":"mod1",
        "modfiles":[
            {
                "url":"http://www.example.com/file2.7z",
                "localpath":"mod1/file2",
                "size":5,
                "sizecompressed":3,
                "checksum":"46aabad952db3e21e273ce"
            },
            {
                "url":"http://www.example.com/file1.7z",
                "localpath":"mod1/file1",
                "size":9,
                "sizecompressed":4,
                "checksum":"862f90bafda118c4d3c5ee6477"
            }
        ]
    },
    {
        "modfolder":"mod2",
        "modfiles":[
            {
                "url":"http://www.example.com/file3.7z",
                "localpath":"mod2/file3",
                "size":8,
                "sizecompressed":4,
                "checksum":"cb1e69de0f75a81bbeb465ee0cdd8232"
            },
            {
                "url":"http://www.example.com/file1.7z",
                "localpath":"mod2/file1",
                "size":9,
                "sizecompressed":4,
                "checksum":"862f90bafda118c4d3c5ee6477"
            }
        ]
    }
]}

客户端文件结构,应该在同步后

    mod1/
         file2
         file1
    mod2/
         file3
         file1

// mod1/file2 == mod2/file2

关于存储库的一个特殊事项: 从服务器获取的存储库仅代表更大存储库的子集,因为用户只需要一个正在改变(也重叠)的子树。 有时,存储库由mod1和mod2组成,有时是mod1和mod3,依此类推。

工作要做:

  • 下载存储库并解析它(Net I / O)
  • 在流程结束时标记不在存储库中的文件以供删除(文件可能因相同的校验和而被复制)(文件I / O)
  • 如果文件存在:检查现有文件的校验和(校验和缓存)(文件I / O)
  • 如果文件不存在:检查checksumcache是​​否有其他子树中的相同文件复制文件而不是下载文件(Light文件I / O)
  • 以压缩格式下载单个文件(Net I / O)
  • 提取压缩文件(文件I / O)
  • 未压缩文件的校验和(文件I / O)
  • 与文件关联的缓存校验和。 (轻文件I / O)

我的解决方案:(许多不同的生产者/消费者)

  • Checksum缓存使用MapDB持久映射。
  • 仅使用ATM md5校验和。
  • 队列:每个Workertype都有一个阻塞队列(生产者/消费者)
  • 线程池:每个Workertype都有一个固定的Threadpool,例如: 3 Downloader,2 Checksum,...
  • 工作人员将当前工作分配到其他队列:Downloader - >提取 - >校验和

Workertypes:

  • Localfile Worker:检查本地文件结构(使用校验和缓存), 将工作重定向到Download-Worker,Delete-Worker
  • 复制:将具有相同校验和的文件复制到目标
  • 下载:下载文件
  • 校验和:校验和文件并插入ch​​ecksumcache
  • 删除:删除文件
  • 提取:提取压缩文件

1 个答案:

答案 0 :(得分:2)

  

平行这些工作的最佳策略是什么?

你有I / O.并且,可能如果一个目录上的一个作业已在进行中,则另一个作业不能同时在同一目录上运行。

所以,你需要在这里锁定。建议:在文件系统上使用锁定目录,并使用目录而不是文件来锁定。为什么?因为目录创建是原子的(第一个原因),并且因为Java 6不支持原子文件创建(第二个原因)。实际上,您甚至可能需要两个锁定目录:一个用于内容下载,另一个用于内容处理。

你已经完成了下载与处理的分离,所以我在这里没有更多的内容;)

我不确定你为什么要缓存校验和呢?它看起来对我没什么用......

另外,我不知道你要处理的文件有多大,但是为什么还要检查现有的目录内容等而不是提取新目录并重命名?即:

  • newdir;
  • 中提取新目录
  • 校验;
  • dstdir移至dstdir.old;
  • newdir移至dstdir;
  • 废料dstdir.old

这甚至意味着您可以并行化报废,但这是太多的I / O并行化......您将不得不限制执行实际I / O的线程数。

编辑以下是我将如何分开处理:

  • 首先,归档本身不再有校验和,但归档中有一个文件,其中包含每个文件的MD5总和(例如,MD5SUMS);
  • 两个阻止队列:下载 - >替换,替换 - >报废;
  • 一个处理器负责下载;当它完成后,它会填充下载 - >替换队列;
  • 另一个处理器从下载中选择任务 - >替换队列;此任务按顺序执行取消归档和校验和;如果两者都是正确的,如上所述,它重命名现有目录,将解压缩的目录重命名为预期目录,并在替换上放置一个报废任务 - > scrappint queue;
  • 第三个也是最后一个处理器,从报废队列中选择一个任务并执行删除以前的存档。

请注意,如果校验和很重,则可以并行化。