【问题标题】:Thread safe math operations in Parallel on Apache AntApache Ant 上的并行线程安全数学运算
【发布时间】:2015-01-13 14:52:37
【问题描述】:

我正在与 Ant 并行运行几个子任务。

这是build.xml的简化内容:

<target name="parallelOperations">
    <var name="port.number" value="9006"/>
    <for list="a,b,c,d,e" param="letter" parallel="true">
        <sequential>
            <echo>Letter @{letter}</echo>
            <math result="port.number" operand1="${port.number}" operation="+" operand2="1" datatype="int"/>
            <echo>${port.number}</echo>
        </sequential>
    </for>
</target>

这是主要结果:

 [echo] Letter c
 [echo] Letter b
 [echo] Letter a
 [echo] Letter d
 [echo] Letter e
 [echo] 9007
 [echo] 9007
 [echo] 9007
 [echo] 9007
 [echo] 9007

这里发生的是对于列表的每个元素,它打印元素的内容和加号操作的结果。这里的问题是数学运算不是线程保存的,意味着每个运算同时访问变量$port.number,加一个值,然后赋值。

有没有办法用 Ant 做到线程安全?我尝试做的是每个并行运行的子任务,获取一个唯一的端口号。如果有任何其他方法可以做到这一点,它也可能是一个很好的解决方案。

【问题讨论】:

    标签: multithreading ant parallel-processing ant-contrib


    【解决方案1】:

    这是来自documentation of parallel

    &lt;parallel&gt; 的主要用例是同时运行外部程序(例如应用程序服务器)以及 JUnit 或 TestNG 测试套件。任何试图同时运行大型 Ant 任务序列(例如 javadoc 和 javac)的人,都隐含地承担了识别和修复它们运行的​​任务的所有并发错误的任务

    因此,同步操作取决于用户。可能有两种解决方案:

    1. 要么使用waitfor 任务让每个线程等待某个条件为真(例如,设置了一个属性)。

    2. 实现您自己的同步任务。 This link 描述了一种编写可以获取 id 并锁定它的任务的方法。

    第一个解决方案更简单,通常用于这种同步。

    【讨论】:

    • 等待对我来说还不够。问题 2 上的同步链接的 Stefan Frank 的实现是正确的。谢谢!
    【解决方案2】:

    我将回答我自己的问题并发布具体解决方案,以防万一有人需要。

    这是可行的解决方案:

    <target name="ParallelOperations">
    <var name="port.number" value="9006"/>
    <for list="a,b,c,d" param="letter" parallel="true">
        <sequential>
            <echo>Letter @{letter}</echo>
            <!-- Synchronize the port number -->
            <synchronized id="port.number.lock">
                <echo>@{letter} new port ${port.number}</echo>
                <var name="@{letter}.port.number" value="${port.number}" />
                <math result="port.number" operand1="${port.number}" operation="+" operand2="1" datatype="int"/>
            </synchronized>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            <echo>@{letter} ${@{letter}.port.number}</echo>
            </sequential>
    </for>
    

    结果如下:

    ParallelOperations:
         [echo] Letter d
         [echo] Letter a
         [echo] Letter c
         [echo] Letter b
         [echo] c new port 9006
         [echo] c 9006
         [echo] b new port 9007
         [echo] c 9006
         [echo] c 9006
         [echo] b 9007
         [echo] c 9006
         [echo] a new port 9008
         [echo] b 9007
         [echo] c 9006
         [echo] b 9007
         [echo] c 9006
         [echo] a 9008
         [echo] d new port 9009
         [echo] c 9006
         [echo] b 9007
         [echo] a 9008
         [echo] d 9009
         [echo] b 9007
         [echo] a 9008
         [echo] d 9009
         [echo] c 9006
         [echo] a 9008
         [echo] b 9007
         [echo] d 9009
         [echo] a 9008
         [echo] b 9007
         [echo] d 9009
         [echo] a 9008
         [echo] b 9007
         [echo] d 9009
         [echo] a 9008
         [echo] d 9009
         [echo] a 9008
         [echo] d 9009
         [echo] d 9009
    

    从@manouti 的回答中,我选择了 Stefan Fanke 的同步命令,并使用每个字母创建一个特定的变量来存储端口号。

    如您所见,每个字母都分配有自己唯一的端口号。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-06
      • 2012-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      相关资源
      最近更新 更多