1 / 39

מבוא מורחב למדעי המחשב

מבוא מורחב למדעי המחשב. תרגול 14. Serial Programming. Expressions are evaluated in a well-known order One expression at a time Life are easy (though slow). Concurrent (Parallel) Computation. Some code parts are “parallel” to each other Order of evaluation is not well-defined

garron
Download Presentation

מבוא מורחב למדעי המחשב

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. מבוא מורחב למדעי המחשב תרגול 14

  2. Serial Programming • Expressions are evaluated in a well-known order • One expression at a time • Life are easy (though slow)

  3. Concurrent (Parallel) Computation • Some code parts are “parallel” to each other • Order of evaluation is not well-defined • Typically depends on an internal OS mechanism which we can assume (almost) nothing about

  4. Why parallel programming?

  5. Why parallel programming? Because it can be faster! (define (P i) (let ((counter (+ 1 (* (- i 1) (power 10 9)))) (upto (* i (power 10 9)))) (define (iter) (if (< counter upto) (begin (if (prime? counter) (display counter) #f) (increment-counter) (iter)) 'done)) (iter))) (parallel-execute (P 1) (P 2) ... (P 10))

  6. faster • Can be faster even on a single computer (dual-core) • Even on a single-core, things can happen in parallel • Mainly CPU vs. I\O (disk access, communication…) • But we need to parallelize wisely

  7. Always parallelize? • No • Parallel programs are harder to write and are more error prone • Also, if designed badly, can be even slower than sequential • Parallelize when you can gain something, or when you have to

  8. Why Parallelize? • Because life are parallel! • Say that you’ve built a desktop application • Receives a query from the user, processes it and returns an answer

  9. MindReader (define (MindReader) (display “Enter your name”) (let ((name (read))) (ReadMind name)) (MindReader) )

  10. But reading minds takes time… (define (MindReader) (display “Enter your name”) (let ((name (read))) (begin (display “Thinking…”) (ReadMind name))) (MindReader) )

  11. Put it on the web! (define (MindReader) (display “Enter your name”) (let (name (readMessage)) (begin (display “Thinking…”) (let ((result (ReadMind name))) (display result)))) (MindReader) )

  12. Won’t work • Say that reading minds takes only 5 seconds • If only 20 people asked for it before I did, I should wait almost 2 minutes • And I don’t even get a message • And probably my message is thrown away • Parallel Programming to the rescue! • But how?

  13. Tactics • MindReader is a black-box, can’t change it • But can separate web-interface from reading minds • One process will receive messages, the other will read minds, and a third will print results • How to communicate?

  14. rear-ptr front-ptr queue a b c d Queue Helper Procedures Hidden inside the abstraction (define (front-ptr q) (cadr q)) (define (rear-ptr q) (cddr q)) (define (set-front-ptr! q item) (set-car! (cdr q) item)) (define (set-rear-ptr! q item) (set-cdr! (cdr q) item))

  15. Queue implementation (define (make-queue) (cons 'queue (cons null null))) (define (queue? q) (and (pair? q) (eq? 'queue (car q)))) (define (empty-queue? q) (if (not (queue? q)) (error "object not a queue:" q) (null? (front-ptr q)))) (define (front-queue q) (if (empty-queue? q) (error "front of empty queue:" q) (car (front-ptr q))))

  16. new-pair rear-ptr rear-ptr front-ptr queue e a b c d Queue implementation – Insert (define (insert-queue! q elt) (let ((new-pair (cons elt nil))) (cond ((empty-queue? q) (set-front-ptr! q new-pair) (set-rear-ptr! q new-pair) ‘ok) (else (set-cdr! (rear-ptr q) new-pair) (set-rear-ptr! q new-pair) ‘ok))))

  17. pop-queue! (define (pop-queue! q) (let ((result (front-queue q))) (begin (delete-queue! q) result))))

  18. Application Workflow ReadAndSave ExtractAndProcess ExtractAndPrint requests results

  19. New interface function (define (ReadAndSave q) (display “Enter your name”) (let ((name (readMessage))) (begin (display “Your message was received”) (insert-queue! q name))) (ReadAndSave q) )

  20. Processing message (define (ExtractAndProcess q-in q-out) (let ((name (pop-queue! q-in)) (let ((result (ReadMind name))) (insert-queue! q-out result))) (ExtractAndProcess q-in q-out) )

  21. Printing the result (define (ExtractAndPrint q) (let ((result (pop-queue! q))) (display result)) (ExtractAndPrint q) )

  22. Putting it all together (define (myWebApplication) (let ((q-requests (make-queue)) (q-results (make-queue))) (parallel-execute (ReadAndSave q-requests) (ExtractAndProcessq-requests q-results) (ExtractAndPrintq-results))))

  23. A Problem • One process might try to access the queue while the other is inserting • A message might get lost • We need Mutual Exclusion

  24. Mutual Exclusion • The problem rises in case of a shared object • We can’t have two processes writing to it in the same time • In the vast majority of cases, read+write is forbidden as well • read+read is sometimes ok, depends on the case

  25. Mutex • A synchronization object • A process can request for access • It will be granted access only if no one is holding the mutex • Otherwise wait

  26. New interface function (define (ReadAndSave q m) (display “Enter your name”) (let ((name (readMessage))) (begin (display “Your message was received”) (m 'begin) (insert-queue! q name) (m 'end)) (ReadAndSave q m) )

  27. New processing message (define (ExtractAndProcess q-in m-in q-out m-out) (m-in ‘begin) (let ((name (pop-queue! q-in)) (m-in ‘end) (let ((result (ReadMind name))) (begin (m-out ‘begin) (insert-queue! q-out result) (m-out ‘end)))) (ExtractAndProcess q-in m-in q-out m-out) )

  28. Printing the result (define (ExtractAndPrint q m) (m ‘begin) (let ((result (pop-queue! q))) (begin (m ‘end) (display result))) (ExtractAndPrint q m) )

  29. Putting it all together (new) (define (myWebApplication) (let ((q-requests (make-queue)) (m-requests (make-mutex)) (q-results (make-queue))) (m-results (make-mutex))) (parallel-execute (ReadAndSave q-requests m-requests) (ExtractAndProcess q-requests m-requests q-results m-results) (ExtractAndPrint q-results m-results))))

  30. A better solution • Put a mutex within the queue object • We’ll create a new object: secure-mutex • Don’t throw away the old queue, though

  31. Secure-Queue implementation (define (make-secure-queue) (cons (make-mutex) (cons ‘secure-queue (cons null null)) (define (mutex q) (car q) (define (secure-queue? q) (and (pair? q) (pair? (cdr q)) (eq? ‘secure-queue (cadr q)))) (define (empty-secure-queue? q) (if (not (secure-queue? q)) (error "object not a secure queue:" q) (begin((mutex q) ‘begin) (let ((res (null? (front-ptr q)))) ((mutex q) ‘end) res) )))

  32. front-secure-queue (define (front-secure-queue q) (if (empty-secure-queue? q) (error "front of empty queue:" q) (begin ((mutex q) ‘begin) (car (front-ptr q) ((mutexq) ‘end))))

  33. front-secure-queue (define (front-secure-queue q) (if (empty-secure-queue? q) (error "front of empty queue:" q) (begin ((mutex q) ‘begin) (car (front-ptr q) ((mutexq) ‘end)))) Mind the gap!

  34. front-secure-queue (define (front-secure-queue q) (if (empty-secure-queue? q) (error "front of empty queue:" q) (begin ((mutex q) ‘begin) (car (front-ptr q) ((mutexq) ‘end)))) Mind the gap! What about the return value?

  35. front-secure-queue (define (front-secure-queue q) ((mutex q) ‘begin) (if (empty-secure-queue? q) (begin ((mutex q) ‘end) (error "front of empty queue:" q)) (begin (car (front-ptr q)) ((mutex q) ‘end))))) Not all mutex implementations support multiple acquisition

  36. front-secure-queue (define (front-secure-queue q) ((mutex q) ‘begin) (if (empty-queue? q) (begin ((mutex q) ‘end) (error "front of empty queue:" q)) (begin (let ((ret (car (front-ptr q))) ((mutex q) ‘end) ret))))

  37. Insert-secure-queue! (define (insert-secure-queue! q elt) (let ((new-pair (cons elt nil))) (cond ((empty-queue? q) (begin ((mutex q) ‘begin) (set-front-ptr! q new-pair) (set-rear-ptr! q new-pair) ((mutex q) ‘end) ‘ok) (else (begin ((mutexq) ‘begin) (set-cdr! (rear-ptr q) new-pair) (set-rear-ptr! q new-pair) ((mutex q) ‘end) ‘ok)) )))

  38. Insert-secure-queue! (define (insert-secure-queue! q elt) (let ((new-pair (cons elt nil))) (cond ((empty-queue? q) (begin ((mutex q) ‘begin) (set-front-ptr! q new-pair) (set-rear-ptr! q new-pair) ((mutex q) ‘end) ‘ok) (else (begin ((mutex q) ‘begin) (set-cdr! (rear-ptr q) new-pair) (set-rear-ptr! q new-pair) ((mutex q) ‘end) ‘ok)) ))) Need to lock before calling queue-empty?

  39. Where to put the mutex? • Sometimes difficult to decide • Thumb rule – lock as lower as possible, and as little as possible • But note that accessing the locks in real life is costly as well

More Related