第4章 MPI消息传递

进程和线程的异同点

相同点: a) 每个进程都有一个进程控制块,线程也拥有一个线程控制块
b)二者都具有ID,一组寄存器,状态,优先级以及所要遵循的调度策略
不同点:
1.起源不同:
先有进程,后面再有线程

2.概念不同
进程: 进程是程序真正运行起来的实例,是系统分配资源与调度的基本单位
线程: 是CPU调度的基本单位

3.内存共享方式不同
进程: 操作系统给不同进程分配一定的内存,不同进程的内存通常不共享。除非使用进程间通信xx
线程: 一个进程里的线程同属于同一个进程,进程间内存共享的,只考虑如何协作分配的问题即可。

4.拥有的资源不同
1.不同线程共享的内容包括:
(1)进程代码段
(2)进程的共有数据

2.不同线程独有的内容包括:
(1)线程ID
(2)线程的堆栈

5.数量不同
一个进程至少包括一个进程,也可以包括多个线程

6.开销不同
(1)线程的创建、中指时间比进程短
(2)同一进程内的线程切换时间 比 进程切换短
(3)同一进程的各个线程间共享内存和文件资源,可以不通过内核进行通信。

云计算

概念:云计算是通过互联网分布计算服务
特点:自由按需访问;网络的泛在访问;快速弹性;可计量的服务;资源共享
架构:前端和后端(图)

给出计算pi的方式,如何实现并行

from mpi4py import MPI
N = 100000
w = 1/N
pi = 0

comm = MPI.COMM_WORLD      #通信器
taskid = comm.Get_rank()   #提供进程的序号
tasknum = comm.Get_size()  #线程总数

for i in range(taskid, N, tasknum):
    local = (i+0.5)*w
    temp = 4/(1+local**2)*w
    pi += temp
# comm.Reduce(local,pi,Op=MPI.SUM,root=0)      #归约操作
pi = comm.gather(local,root=0)       #gather函数聚合通信
if taskid == 0:
    print(pi)

死锁复现

from mpi4py import MPI

comm = MPI.COMM_WORLD      #通信器
taskid = comm.Get_rank()   #提供进程的序号
tasknum = comm.Get_size()  #线程总数
if taskid == 1:
    d5 = comm.recv(5)
    comm.send("hello 5", 5)
    print("task 1 done")
if taskid == 5:
    d1 = comm.recv(1)
    comm.send("hello 1",1)
    print("task 5 done")

在这里插入图片描述

bcast广播通信

from mpi4py import MPI
import time
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()
var_share = 0
for i in range(10):
    if rank == 0:
        var_share += 100
    else:
        time.sleep(1)
    var_share = comm.bcast(var_share,root=0)
    var = var_share + rank
    print(rank, "--->", var_share, "--->", var)
mpiexec -n 50 python src/chap4/bcast-test.py

N皇后问题(未完成)

from mpi4py import MPI

def move_to_right(board: list, rank):
    if board[rank] != len(board)-1:
        board[rank] += 1
    else:
        board[rank] = 1


def chk_broad(board,rank):
    for row,col in enumerate(board):
        if row != 0 and row != rank:
            if col == board[rank]:
                return True
            elif abs(row-rank) == abs(col-board[rank]):
                return True

comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()
board = []
if rank == 0:
    pass
else:
    if chk_broad(board, rank):
        move_to_right()
        

H20生成

在这里插入图片描述

from threading import Semaphore,Lock
class H2O:
    def __init__(self):
        self.O = Semaphore(1)
        self.H = Semaphore(2)
        self.H2O = threading.Barrier(3)

    def hydrogen(self, releaseHydrogen: 'Callable[[], None]') -> None:
        self.H.acquire()
        releaseHydrogen()
        self.H2O.wait()
        self.H.release()

    def oxygen(self, releaseOxygen: 'Callable[[], None]') -> None:
        self.O.acquire()
        releaseOxygen()
        self.H2O.wait()
        self.O.release()

哲学家就餐

方法:一个一个串行吃

from threading import Lock
class DiningPhilosophers:
    def __init__(self):
        self.lock = Lock()
    # call the functions directly to execute, for example, eat()
    def wantsToEat(self,
                   philosopher: int,
                   pickLeftFork: 'Callable[[], None]',
                   pickRightFork: 'Callable[[], None]',
                   eat: 'Callable[[], None]',
                   putLeftFork: 'Callable[[], None]',
                   putRightFork: 'Callable[[], None]') -> None:
        self.lock.acquire()
        pickLeftFork()
        pickRightFork()
        eat()
        putLeftFork()
        putRightFork()
        self.lock.release()

交替打印字符串

在这里插入图片描述

from threading import Semaphore
class FizzBuzz:
    def __init__(self, n: int):
        self.n = n
        self.sem_fizz = Semaphore(0)
        self.sem_buzz = Semaphore(0)
        self.sem_fibu = Semaphore(0)
        self.sem_num = Semaphore(1)

    # printFizz() outputs "fizz"
    def fizz(self, printFizz: 'Callable[[], None]') -> None:
        for i in range(1, self.n+1):
            if i % 3 == 0 and i % 5 != 0:
                self.sem_fizz.acquire()
                printFizz()
                self.sem_num.release()

    # printBuzz() outputs "buzz"
    def buzz(self, printBuzz: 'Callable[[], None]') -> None:
        for i in range(1, self.n+1):
            if i % 3 != 0 and i % 5 == 0:
                self.sem_buzz.acquire()
                printBuzz()
                self.sem_num.release()

    # printFizzBuzz() outputs "fizzbuzz"
    def fizzbuzz(self, printFizzBuzz: 'Callable[[], None]') -> None:
        for i in range(1, self.n+1):
            if i % 3 == 0 and i % 5 == 0:
                self.sem_fibu.acquire()
                printFizzBuzz()
                self.sem_num.release()

    # printNumber(x) outputs "x", where x is an integer.
    def number(self, printNumber: 'Callable[[int], None]') -> None:
        for i in range(1, self.n+1):
            self.sem_num.acquire()
            if i % 3 == 0 and i % 5 == 0:
                self.sem_fibu.release()
            elif i % 3 == 0:
                self.sem_fizz.release()
            elif i % 5 == 0:
                self.sem_buzz.release()
            else:
                printNumber(i)
                self.sem_num.release()

按序打印

在这里插入图片描述

import  threading
class Foo:
    def __init__(self):
        self.f1 = threading.Event()
        self.f2 = threading.Event()

    def first(self, printFirst: 'Callable[[], None]') -> None:
        printFirst()
        self.f1.set()

    def second(self, printSecond: 'Callable[[], None]') -> None:
        self.f1.wait()
        printSecond()
        self.f2.set()

    def third(self, printThird: 'Callable[[], None]') -> None:
        self.f2.wait()
        printThird()
        

交替打印FooBar

两个不同的线程将会共用一个 FooBar 实例:

  • 线程 A 将会调用 foo() 方法,而
  • 线程 B 将会调用 bar() 方法
    请设计修改程序,以确保 “foobar” 被输出 n 次。
    在这里插入图片描述
import threading
class FooBar:
    def __init__(self, n):
        self.n = n
        self.foo_done = threading.Event()
        self.bar_done = threading.Event()

    def foo(self, printFoo: 'Callable[[], None]') -> None:
        self.bar_done.set()
        for i in range(self.n):
            self.bar_done.wait()
            # printFoo() outputs "foo". Do not change or remove this line.
            printFoo()
            self.bar_done.clear()
            self.foo_done.set()

    def bar(self, printBar: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.foo_done.wait()
            # printBar() outputs "bar". Do not change or remove this line.
            printBar()
            self.foo_done.clear()
            self.bar_done.set()

打印零与奇偶数

在这里插入图片描述

import threading
class ZeroEvenOdd:
    def __init__(self, n):
        self.n = n
        self.e0 = threading.Event()
        self.e1 = threading.Event()
        self.e2 = threading.Event()
        
    def zero(self, printNumber) -> None:
        self.e0.set()    
        for i in range(1,self.n+1):
            self.e0.wait()
            printNumber(0)
            self.e0.clear()
            if i%2==0:
                self.e2.set()    
            else:
                self.e1.set()    

    def even(self, printNumber) -> None:
        for i in range(2,self.n+1,2):
            self.e2.wait()
            printNumber(i)
            self.e2.clear() 
            self.e0.set()
        
    def odd(self, printNumber) -> None:
        for i in range(1,self.n+1,2):
            self.e1.wait()
            printNumber(i)
            self.e1.clear() 
            self.e0.set()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值