python学习笔记(进程间通信、多进程和多线程总结)

进程间通信之生产者消费者模型

import multiprocessing
# 线程通信=====(队列) ---- from queue import Queue
# 进程池中进程通信=====(队列) --- from multiprocess.Manager import Queue
# 多进程通信=========(队列)   ---- from multiprocess import Queue
import time
class Producer(multiprocessing.Process):
    def __init__(self, queue):
        super(Producer, self).__init__()
        self.queue = queue
    def run(self):
        # 将需要通信的数据写入队列中;
        for i in range(10):
            self.queue.put(i)
            time.sleep(0.1)
            print("传递消息, 内容为%s" %(i))
class Consumer(multiprocessing.Process):
    def __init__(self, queue):
        super(Consumer, self).__init__()
        self.queue = queue
    def run(self):
        while True:
            time.sleep(0.1)
            recvData = self.queue.get()
            print("接受到另一进程传递的数据: %s" %(recvData))


if __name__ == '__main__':
    q =  multiprocessing.Queue()
    p1 = Producer(q)
    c1 = Consumer(q)

    p1.start()
    c1.start()
    p1.join()
    c1.join()

python学习笔记(进程间通信、多进程和多线程总结)_第1张图片

进程间通信之管道

1). Pipe管道,进程间通信的方式, l类似于 ls | wc -l;
2). Pipe()返回两个连接对象, 分别代表管道的两边;
3). 管道通信操作的方法: send(), recv;
4). 管道间的通信是双向的, 既可以发送,也可以接收;

import multiprocessing
# 线程通信=====(队列) ---- from queue import Queue
# 进程池中进程通信=====(队列) --- from multiprocess.Manager import Queue
# 多进程通信=========(队列)   ---- from multiprocess import Queue
import time
def after(conn):
    while True:
        print("接收到数据:", conn.recv())
        time.sleep(1)
def before(conn):
    while True:
        data = [42, None, 34, 'hello']
        conn.send(data)
        print("正在发送数据:%s" % (data))
        time.sleep(1)

def main():
    # send recv
    before_conn, after_conn = multiprocessing.Pipe()

    p1 = multiprocessing.Process(target=after, args=(after_conn,))
    p1.start()

    p2 = multiprocessing.Process(target=before, args=(before_conn,))
    p2.start()

    p1.join()
    p2.join()


if __name__ == '__main__':
    main()

python学习笔记(进程间通信、多进程和多线程总结)_第2张图片

分布式进程

  • 遇到大型计算任务,一台主机无法完成时,需要多台主机进行计算
  • 管理端
import random
from queue import  Queue
# BaseManager: 提供了不同机器之间共享数据的一种方法(ip:port)
from multiprocessing.managers import  BaseManager

# 1. 创建存储任务需要的队列
task_queue = Queue()

# 2. 存储任务执行结果的队列
result_queue = Queue()


# 3. 将队列注册到网上(使得其他主机也可以访问)
BaseManager.register('get_task_queue', callable=lambda : task_queue)
BaseManager.register('get_result_queue', callable=lambda : result_queue)


# 绑定ip和端口, 并且来个暗号;
manager = BaseManager(address=('172.25.60.250', 4000), authkey=b'westos')


# 4. 启动manager对象, 开始共享队列
manager.start()
# 5. 通过网络访问共享的Queue对象;
# BaseManager.register会注册一个方法, 当调用方法时, 执行函数lambda : task_queue;
task = manager.get_task_queue()
result = manager.get_result_queue()

# 6. 往队列里面放执行任务需要的数据;
for i in range(1000):
    # 模拟有1000个数字;
    n = random.randint(1, 100)
    task.put(n)
    print("任务列表中加入任务: %d" %(n))

# 7. 从result队列中读取各个机器中任务执行的结果;
for i in range(1000):
    res = result.get()
    print("队列任务执行的result: %s" %(res))


#  8. 关闭manager对象, 取消共享的队列
manager.shutdown()

  • 被管理端1
import time
from multiprocessing.managers import BaseManager

# 1. 连接Master端, 获取共享的队列;ip是master端的ip, port'也是master端manager进程绑定的端口;
slave = BaseManager(address=('172.25.60.250', 4000), authkey=b'westos')

# 2. 注册队列, 获取共享的队列内容;
BaseManager.register('get_task_queue')
BaseManager.register('get_result_queue')

# 3. 连接master端;
slave.connect()

# 4. 通过网络访问共享的队列;
task = slave.get_task_queue()
result = slave.get_result_queue()

# 5. 读取管理端共享的任务, 并依次执行;
for i in range(500):
    n = task.get()
    print("slave1 运行任务 %d ** 2: " % (n))
    res = "slave1: %d ** 2 = %d" % (n, n ** 2)
    time.sleep(1)
    # 将任务的运行结果放入队列中;
    result.put(res)

print("执行结束........")
  • 被管理端2
import time
from multiprocessing.managers import BaseManager

# 1. 连接Master端, 获取共享的队列;ip是master端的ip, port'也是master端manager进程绑定的端口;
slave = BaseManager(address=('172.25.60.250', 4000), authkey=b'westos')

# 2. 注册队列, 获取共享的队列内容;
BaseManager.register('get_task_queue')
BaseManager.register('get_result_queue')

# 3. 连接master端;
slave.connect()

# 4. 通过网络访问共享的队列;
task = slave.get_task_queue()
result = slave.get_result_queue()

# 5. 读取管理端共享的任务, 并依次执行;
for i in range(500):
    n = task.get()
    print("slave2: 运行任务 %d ** 2: " % (n))
    res = "slave2: %d ** 2 = %d" % (n, n ** 2)
    time.sleep(1)
    # 将任务的运行结果放入队列中;
    result.put(res)

print("执行结束........")

python学习笔记(进程间通信、多进程和多线程总结)_第3张图片
python学习笔记(进程间通信、多进程和多线程总结)_第4张图片
python学习笔记(进程间通信、多进程和多线程总结)_第5张图片

多进程和多线程总结

1.什么是进程?什么是线程?

进程是表示资源分配的基本单位,又是调度运行的基本单位。
例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,
包括各种表格、内存空间、磁盘空间、I/O设备等。然后,把该进程放
人进程的就绪队列。进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行。

线程是进程中执行运算的最小单位,如果把进程理解为在逻辑上操作系统所完成的任务,
那么线程表示完成该任务的许多可能的子任务之一。例如,假设用户启子任务;在产生
工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务。

多线程就像是火车上的每节车厢,而进程就是火车。

2.多进程和多线程的区别?

1——进程
2——线程

  • 数据共享、同步:
    1). 数据共享复杂,需要用IPC;数据是分开的,同步简单
    2). 因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂
    各有优势
  • 内存、CPU
    1). 占用内存多,切换复杂,CPU利用率低
    2). 占用内存少,切换简单,CPU利用率高
    线程占优
  • 创建销毁、切换
    1). 创建销毁、切换复杂,速度慢
    2). 创建销毁、切换简单,速度很快
    线程占优
  • 编程、调试
    1). 编程简单,调试简单
    2). 编程复杂,调试复杂
    进程占优
  • 可靠性
    1). 进程间不会互相影响
    2). 一个线程挂掉将导致整个进程挂掉
    进程占优
  • 分布式
    1). 适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单
    2). 适应于多核分布式
    进程占优

3.进程之间的通信方式以及优缺点?

管道, 信号量, 信号, 消息队列, 共享内存, 套接字

4.线程之间的通信方式?

锁机制:包括互斥锁、条件变量、读写锁
信号量机制(Semaphore)
信号机制(Signal)

5.什么时候用多线程?什么时候用多进程?

1)需要频繁创建销毁的优先用线程
2)需要进行大量计算的优先使用进程
3)可能要扩展到多机分布的用进程,多核分布的用线程

你可能感兴趣的:(笔记)