Gruppen 2 und 4
Samuel Teuber
propa@teuber.dev
https://teuber.dev/propa
Es sollen Kanten in einem Bild (angegeben durch eine Matrix bestehend aus Pixeln) detektiertwerden. Hierfür können Faltungsmatrizen zur Kantendetektion angewandt werden, welche für jeden Pixel des Bildes einen Farbgradienten berechnen. Eine Faltungsmatrix beschreibt hierbeifür einen Pixel, welche der umliegenden Pixel für die Berechnung des Gradienten verwendet werden und den gewichteten Einfluss jedes umliegenden Pixels auf den Gradienten.
Parallelisierungsmethodologie?
Datenparallelismus!
Es soll ein Integral numerisch berechnet werden.
Parallelisierungsmethodologie?
Datenparallelismus!
Es soll einen Webserver programmiert werden, der mehrere Anfragen bearbeiten kann.
Parallelisierungsmethodologie?
Taskparallelismus!
#include<stdio.h>
int global[] = {1, 2, 3, 4, 5};
int *magic(int x[],int y) {
printf("m");
global[1] = *(global + y) + 3;
return&x[y - 2];
}
int main() {
printf("%i", *magic(&global[1], *(global + 1)));
return 0;
}
Ausgabe?
m6
int main(int argc, char*argv[]) {
MPI_Init(&argc, &argv);
int my_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if (my_rank < 2) {
int other_rank = 1 - my_rank;
int tag = 0;
char message[14];
sprintf(message, "Hello, I am %d", my_rank);
MPI_Status status;
MPI_Send(message, strlen(message) + 1, MPI_CHAR, other_rank, tag,MPI_COMM_WORLD);
MPI_Recv(message, 100, MPI_CHAR, other_rank, tag, MPI_COMM_WORLD, &status);
printf("%s\n", message);
}
MPI_Finalize();
return EXIT_SUCCESS;
}
Kommunikationsmodus (Buffered vs. Synchronized/Ready)
MPI_Bsend
MPI_Buffer_attach
MPI_Isend
)MPI_Sendrecv
oder MPI_Sendrecv_replace
Funktion: Erhöht alle Werte von elements
um Differenz zwischen null und kleinstem Wert in Array, falls kleinster Wert kleiner null
MPI_Bcast(&offset, 1, MPI_INT, rootRank, MPI_COMM_WORLD);
int localOffet = 0;
for (int i = 0; i < elementsPerProcess; i++) {
if (local[i] < localOffset) localOffset = local[i];
}
MPI_Reduce(&localOffset, &offset, 1, MPI_INT, MPI_MIN, rootRank, MPI_COMM_WORLD);
|void my_int_sum_reduce(int *sendbuf, int *recvbuf, int count, int root, MPI_Comm comm) {
| int size, rank;
| MPI_Comm_size(comm,&size);
| MPI_Comm_rank(comm,&rank);
| if (rank == root) {
| for (int i = 0; i<count; i++) {
| recvbuf[i] = sendbuf[i]
| }
| for (int i = 0; i < size; i++) {
| if (i == root) continue;
|
| int other[count];
| MPI_Recv(other, count, MPI_INT, i, 0, comm, MPI_STATUS_IGNORE);
| for (int j = 0; j < count; j++)
| recvbuf[j] += other[j];
| }
| } else {
| MPI_Send(sendbuf, count, MPI_INT, root, 0, comm);
| }
|}
class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Functional Interfaces: Interface mit einzelner Funktion
@FunctionalInterface
interface Predicate {
boolean check(Integer value);
}
//...
public int sum(List<Integer> values, Predicate predicate) {
//...
}
Method References: Methodenreferenz als Argument für Funktionsinterface
public class SimpleCheckers {
public static boolean checkSomething(Integer value) { /*...*/ }
}
sum(values, SimpleCheckers::checkSomething)
sum(values, (Integer v) -> v>0);
Beispiel: Java1
(new Thread())->setPriority(int priority)
beeinflusst werdenBeispiel: Java2
Executed complete or not at all
long
oder double
)volatile
VariablenNICHT: a++
Critical Section darf nur von einzigem Thread betreten werden
Performance vs Korrektheit: Amdahl's Law
public void doSomething() {
synchronized(someObject) {
// critical section for someObject
}
}
public synchronized void doSomething() {
// critical section for doSomething
}
decrement
Methode (ohne Race Condition) hinzu?Philosophenproblem:
Java4
while(!condition) {}
busy waiting!
Besser:
while(!condition) {wait();}
notify()
notifyAll()
Warum trotzdem while
?
Java3
class Producer extends Thread {
private Queue queue;
public Producer(Queue queueParam) {
this.queue = queueParam;
}
public void run() {
while(true) {
queue.produce(new Task(ThreadLocalRandom.current().nextInt(0, 100), ThreadLocalRandom.current().nextInt(0, 100)));
}
}
}
class Consumer extends Thread {
private Queue queue;
public Consumer(Queue queueParam) {
this.queue = queueParam;
}
public void run() {
while (true) {
Task t = this.queue.consume();
System.out.println(t.add());
}
}
}
Zu Hause anschauen...
public class Main {
static int flag = 0;
public static void main(String[] args) {
Thread t1 = new Thread(() -> flag = 1);
Thread t2 = new Thread(() -> {
System.out.print(flag);
System.out.print(flag);
});
t1.start();
t2.start();
}
}
Ausgabe 00
- Warum?
t2
wird vor t1
ausgeführtt1
wird vor zweitem sysout in t2
ausgeführt werden, aber flag
in Cache von t2
Lösung: volatile flag
public class Main {
public static void main(String[] args) {
State state = new State();
(new Thread( () -> {
state.a = 1;
state.b = 1;
state.c = state.a + 1;
})).start();
(new Thread( () -> {
if(state.c == 2 && state.b == 0) {
System.out.println("Wrong");
}
})).start();
}
}
public class State {
int a = 0;
int b = 0;
int c = 0;
}
Ausgabe: Wrong
Instruction reordering - tatsächlich ausgeführt in Thread 1:
state.a = 1;
state.c = state.a + 1;
state.b = 1;
Lösung: volatile int c = 0;
java.util.concurrent.atomic
Bsp: AtomicInteger
int get()
int incrementAndGet()
int decrementAndGet()
bool compareAndSet(int oldValue, int newValue)
Zurück zum Counter Beispiel
ReentrantLock
Lock lock= new ReentrantLock(false);
// ...
lock.lock();
c++;
lock.unlock();
Semaphore
Semaphore sem = Semaphore(int capacity, boolean fair);
// ...
sem.acquire();
c++
sem.release();
CyclicBarrier(int n)
(reentrant)CountDownLatch(int n)
(nicht reentrant)ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
String threadName = Thread.currentThread().getName();
System.out.println("Hello " + threadName);
});
try{
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch(InterruptedExceptionex) {
} finally { if(!executor.isTerminated()) { executor.shutdownNow(); }}
Auch: newFixedThreadPool(int c)
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<Integer>> list;
// ....
for (int i= 0; i< 10; i++) {
final int currentValue= i;
Callable<Integer> myCallable= () -> { return fib(currentValue); };
list.add(executorService.submit(myCallable));
// Abrufbar mit
Integer result = future.get();
}
// ...
for(Future<Integer> curFuture : list) {
Integer result = curFuture;
// ...
}
executorService.shutdownNow();