Как распараллелить этот заводной код? - PullRequest
4 голосов
/ 26 мая 2010

Я пытаюсь написать повторно используемый компонент в Groovy, чтобы легко отбрасывать электронные письма из некоторых наших Java-приложений. Я хотел бы передать ему Список, где Электронная почта - это просто POJO (POGO?) С некоторой информацией по электронной почте. Я бы хотел, чтобы он был многопоточным, по крайней мере, выполнял всю логику электронной почты во втором потоке или создавал один поток на каждое электронное письмо

Я очень туманно отношусь к многопоточности в Java, так что, вероятно, это не поможет! Я пробовал несколько разных способов, но вот что у меня есть сейчас:

void sendEmails(List<Email> emails) {

    def threads = []

    def sendEm = emails.each{ email ->
        def th = new Thread({
            Random rand = new Random()
            def wait = (long)(rand.nextDouble() * 1000)
            println "in closure"
            this.sleep wait
            sendEmail(email)
        })
        println "putting thread in list"
        threads << th
    }

    threads.each { it.run() }
    threads.each { it.join() }

}

Я надеялся, что сон будет случайным образом замедлять некоторые потоки, чтобы вывод консоли не был последовательным. Вместо этого я вижу это:

putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
in closure
sending email1
in closure
sending email2
in closure
sending email3
in closure
sending email4
in closure
sending email5
in closure
sending email6
in closure
sending email7
in closure
sending email8
in closure
sending email9
in closure
sending email10

sendEmail в основном делает то, что вы ожидаете, включая оператор println и клиент, который вызывает это следующим образом,

void doSomething() {

    Mailman emailer = MailmanFactory.getExchangeEmailer()

    def to = ["one","two"]
    def from = "noreply"

    def li = []
    def email   
    (1..10).each {
        email = new Email(to,null,from,"email"+it,"hello")
        li << email
    }

    emailer.sendEmails li
}

Ответы [ 2 ]

12 голосов
/ 27 мая 2010

Чтобы ваш пример работал параллельно, вам нужно заменить строку

threads.each { it.run() }

с

threads.each { it.start() }

, поскольку run() не запускает новый поток, поэтому ваш код выполнялся последовательно.

Также доступно расширение Groovy под названием GPars . Он поддерживает несколько методов параллелизма, таких как Fork / Join или модель Actor. Используя GPars, ваш код может быть упрощен до следующего:

def sendEmails(emails) {

  GParsPool.withPool {
    emails.eachParallel { email ->
      def wait = (long) new Random().nextDouble() * 1000 
      println "in closure"
      this.sleep wait
      sendEmail(email)
    }
  }

}
2 голосов
/ 26 мая 2010

В паре версий Java (1.5) они представили некоторые новые возможности параллелизма, которые упрощают многопоточность Java (даже больше). Google для java ThreadExecutor, и вы найдете несколько страниц, таких как:

http://www.deitel.com/articles/java_tutorials/20051126/JavaMultithreading_Tutorial_Part4.html

Можно ли сказать, что Groovy еще проще, я не могу сказать, но вы, возможно, захотите применить «новые» методы Java к своему примеру Java, прежде чем проводить сравнение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...