La concurrència és un aspecte crucial en el desenvolupament de programari modern, especialment quan es tracta de millorar el rendiment i la capacitat de resposta de les aplicacions. Groovy proporciona diverses eines i biblioteques per gestionar la concurrència de manera eficient. En aquest tema, explorarem els conceptes bàsics de la concurrència, les eines que Groovy ofereix i com utilitzar-les en els teus projectes.

Conceptes Bàsics de Concurrència

Abans de submergir-nos en les eines específiques de Groovy, és important entendre alguns conceptes bàsics de concurrència:

  • Thread: Un fil d'execució és la unitat bàsica de processament que pot executar codi de manera independent.
  • Process: Un procés és una instància d'un programa en execució que pot contenir múltiples fils.
  • Race Condition: Una condició de carrera ocorre quan dos o més fils accedeixen a dades compartides i intenten canviar-les simultàniament.
  • Deadlock: Un bloqueig mutu es produeix quan dos o més fils esperen indefinidament que els altres alliberin recursos.

Eines de Concurrència en Groovy

Groovy proporciona diverses eines per gestionar la concurrència, incloent:

  1. GPars (Groovy Parallel Systems)
  2. Executors
  3. Futures
  4. Actors

GPars (Groovy Parallel Systems)

GPars és una biblioteca poderosa que facilita la programació concurrent i paral·lela en Groovy. Proporciona diversos models de concurrència, com ara actors, agents, dades paral·leles i més.

Exemple: Utilitzant Actors amb GPars

@Grab(group='org.codehaus.gpars', module='gpars', version='1.2.1')
import groovyx.gpars.actor.Actors

def actor = Actors.actor {
    loop {
        react { message ->
            println "Received: $message"
            if (message == "stop") {
                stop()
            }
        }
    }
}

actor << "Hello"
actor << "World"
actor << "stop"

Explicació:

  • @Grab: Anotació per descarregar la dependència de GPars.
  • Actors.actor: Crea un nou actor.
  • loop: Manté l'actor en execució contínua.
  • react: Defineix com l'actor ha de reaccionar als missatges rebuts.
  • stop: Atura l'actor.

Executors

Els executors són una manera de gestionar un grup de fils de manera eficient. Groovy utilitza la biblioteca java.util.concurrent per proporcionar executors.

Exemple: Utilitzant Executors

import java.util.concurrent.Executors

def executor = Executors.newFixedThreadPool(3)

(1..5).each { i ->
    executor.submit {
        println "Task $i is running on thread ${Thread.currentThread().name}"
    }
}

executor.shutdown()

Explicació:

  • Executors.newFixedThreadPool(3): Crea un grup de fils amb 3 fils.
  • submit: Envia una tasca al grup de fils per a la seva execució.
  • shutdown: Atura l'acceptació de noves tasques i finalitza les tasques existents.

Futures

Els futures representen el resultat d'una operació asíncrona que es completarà en el futur.

Exemple: Utilitzant Futures

import java.util.concurrent.Executors
import java.util.concurrent.Callable

def executor = Executors.newSingleThreadExecutor()

def future = executor.submit({ -> 
    Thread.sleep(2000)
    return "Result after 2 seconds"
} as Callable)

println "Waiting for the result..."
println "Result: ${future.get()}"

executor.shutdown()

Explicació:

  • submit: Envia una tasca callable al grup de fils.
  • future.get(): Espera fins que la tasca es completi i retorna el resultat.

Actors

Els actors són una manera de gestionar la concurrència mitjançant la comunicació de missatges entre entitats independents.

Exemple: Utilitzant Actors

@Grab(group='org.codehaus.gpars', module='gpars', version='1.2.1')
import groovyx.gpars.actor.Actors

def actor = Actors.actor {
    loop {
        react { message ->
            println "Received: $message"
            if (message == "stop") {
                stop()
            }
        }
    }
}

actor << "Hello"
actor << "World"
actor << "stop"

Explicació:

  • Actors.actor: Crea un nou actor.
  • loop: Manté l'actor en execució contínua.
  • react: Defineix com l'actor ha de reaccionar als missatges rebuts.
  • stop: Atura l'actor.

Exercicis Pràctics

Exercici 1: Utilitzant Executors

Crea un grup de fils que executi 10 tasques, cadascuna imprimint el seu número de tasca i el nom del fil.

Solució:

import java.util.concurrent.Executors

def executor = Executors.newFixedThreadPool(5)

(1..10).each { i ->
    executor.submit {
        println "Task $i is running on thread ${Thread.currentThread().name}"
    }
}

executor.shutdown()

Exercici 2: Utilitzant Futures

Crea una tasca asíncrona que retorni un missatge després de 3 segons i imprimeix el resultat.

Solució:

import java.util.concurrent.Executors
import java.util.concurrent.Callable

def executor = Executors.newSingleThreadExecutor()

def future = executor.submit({ -> 
    Thread.sleep(3000)
    return "Result after 3 seconds"
} as Callable)

println "Waiting for the result..."
println "Result: ${future.get()}"

executor.shutdown()

Resum

En aquesta secció, hem explorat els conceptes bàsics de la concurrència i les eines que Groovy proporciona per gestionar-la. Hem vist com utilitzar GPars, executors, futures i actors per crear aplicacions concurrents de manera eficient. La comprensió i l'ús adequat d'aquestes eines poden millorar significativament el rendiment i la capacitat de resposta de les teves aplicacions Groovy.

© Copyright 2024. Tots els drets reservats