进程补充 | 线程

今日内容概要

  • 僵尸进程余孤儿进程
  • 守护进程
  • 互斥锁
  • 消息队列
  • 实现进程间数据交互(IPC机制)
  • 生产者消费者模型
  • 线程

僵尸进程与孤儿进程

僵尸进程:进程代码运行结束之后并没有直接结束,需要等待回收子进程资源才结束
孤儿进程:主进程非正常死亡,子进程还在运行

守护进程

守护进程:守护某个进程,随着进程的结束而结束

from multiprocessing import Process
import time


def index(name):
    print('%s is running' % name)
    time.sleep(3)
    print('%s is over' % name)


if __name__ == '__main__':
    p = Process(target=index, args=('sss',))
    p.daemon = True  # 设置守护进程(放在start语句前面)
    p.start()
    print('主')

image

互斥锁

将并发编程串行,降低了效率,提高了数据安全性

使用锁注意事项:
      1.一定要在需要的地方加锁,不要随意加
      2.不要轻易的使用锁

from multiprocessing import Process, Lock
import time
import json
import random


# 查票
def cat(name):
    with open(r'data.txt', 'r', encoding='utf8') as f:
        data_dict = json.load(f)
        data_num = data_dict.get('ticket')
    print('%s查看余票%s' % (name, data_num))


# 买票
def buy(name):
    # 先查票
    with open(r'data.txt', 'r', encoding='utf8') as f:
        data_dict = json.load(f)
        data_num = data_dict.get('ticket')
    # 模拟延时
    time.sleep(random.random())
    # 判断是否有票
    if data_num > 0:
        # 将余票减1
        data_dict['ticket'] -= 1
        # 买票
        with open(r'data.txt', 'w', encoding='utf8') as f1:
            json.dump(data_dict, f1, ensure_ascii=False)
        print('%s购买成功' % name)
    else:
        print('没有票了!!!')

image

消息队列

打破进程间默认无法通信的情况

from multiprocessing import Queue

q = Queue(3)  # 括号内填写最大等待数
# 存放数据
q.put(111)
q.put(222)
print(q.full())  # 判断当前队列是否满了
q.put(333)
print(q.full())
# q.put(444)  # 超出范围原地等到,直到有空缺位置
print('满了!!!')
print(q.get())
print(q.get())
print(q.empty())  # 判断队列是否为空
print(q.get())
# print(q.get())  # 没有数据原地等待,直到有数据
# print(q.get_nowait())  # 没有数据立刻报错
print('嘿嘿嘿!!!')

image

实现进程间数据交互(IPC机制)

from multiprocessing import Process, Queue


def producer(q):
    q.put('子进程producer放的数据')


def consumer(q):
    print('子进程consumer取得%s' % q.get())


if __name__ == '__main__':
    q = Queue()
    # q.put('主进程放的数据')
    p = Process(target=producer, args=(q,))
    c = Process(target=consumer, args=(q,))
    p.start()
    c.start()
    # c.join()

image

生产者消费者模型

生产者:负责产生数据
消费者:负责处理数据

需要解决供需不平衡的现象

from multiprocessing import Process, Queue, JoinableQueue
import time
import random


def producer(name, food, q):
    for i in range(10):
        print('%s生产了%s' % (name, food))
        q.put(food)
        time.sleep(random.random())


def consumer(name, q):
    while True:
        print('%s吃了%s' % (name, q.get()))
        q.task_done()


if __name__ == '__main__':
    # q = Queue()
    q = JoinableQueue()
    p = Process(target=producer, args=('sss', '蛋糕', q))
    c = Process(target=consumer, args=('lmx', q))
    p.start()
    c.daemon = True  # 守护进程
    c.start()
    p.join()
    q.join()  # 等待所有数据取干净

image

线程

线程:进程是一个资源单位,真正被CPU执行的是进程里的线程
进程间数据默认是隔离的,但同一个进程里多个线程的数据是共享的

开设线程的两种方式

"""
开设进程需要的操作:
      1.重新申请一块内存空间
      2.将需要的资源导入
开设线程需要的操作:
      上述两个步骤不需要,开设线程比开设进程消耗的资源少
"""

方法一
from threading import Thread
import time


def index(name):
    print('%s is running' % name)
    time.sleep(3)
    print('%s is over' % name)


t = Thread(target=index, args=('sss',))
t.start()
print('主')

方法二
from threading import Thread
import time


class MyClass(Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s is running' % self.name)
        time.sleep(3)
        print('%s is over' % self.name)


obj = MyClass('sss')
obj.start()
print('主')

image

线程对象方法

1.join方法
2.获取进程号(验证同一个进程内可以开设多个线程)
3.active_count统计当前正在活跃的线程数
4.current_thread

from threading import Thread, active_count, current_thread
import time
import os


def index(name):
    # print(os.getpid())
    print(current_thread().name)
    print('%s is running' % name)
    time.sleep(3)
    print('%s is over' % name)


t = Thread(target=index, args=('sss',))
t.start()
# t.join()  # 主线程等待子线程结束在往下运行
# print(os.getpid())  # 验证同一个进程内可以有多个线程
# print(active_count())  # 统计当前活跃的线程数
print(current_thread().name)  # 主线程名称
# print(t.name)  # 子线程名称
print('主')

image

守护线程

"""
主线程结束代表整个进程结束,所以主线程需要等待所有费守护线程结束才可以结束
"""

from threading import Thread
from multiprocessing import Process
import time
def foo():
    print(123)
    time.sleep(3)
    print("end123")
def bar():
    print(456)
    time.sleep(1)
    print("end456")
if __name__ == '__main__':
    t1=Thread(target=foo)
    t2=Thread(target=bar)
    t1.daemon=True
    t1.start()
    t2.start()
    print("main-------")

image

线程数据共享

from threading import Thread

m = 100


def index():
    global m
    m = 666


t = Thread(target=index)
t.start()
t.join()
print(m)

image

线程互斥锁

from threading import Thread, Lock
import time

m = 100


def index():
    global m  # 局部修改全局
    mutex.acquire()  # 抢锁
    num = m
    time.sleep(0.1)
    # 修改数值
    num -= 1
    m = num
    mutex.release()  # 释放锁


l_list = []
mutex = Lock()
for i in range(100):
    t = Thread(target=index, args=(mutex,))
    t.start()
    l_list.append(t)
# 保证所有子线程结束
for t in l_list:
    t.join()
print(m)

image

TCP服务端实现并发

服务端
import socket
from threading import Thread

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen()


def talk(sock):
    while True:
        try:
            data = sock.recv(1024)
            if len(data) == 0:
                break
            print(data.decode('utf8'))
            sock.send(data + b'666')
        except ConnectionResetError as e:
            print(e)
            break
    sock.close()


while True:
    sock, addr = server.accept()
    print(addr)
    # 添加多线程
    t = Thread(target=talk, args=(sock,))
    t.start()

客户端
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))

client.send(b'hello')
data = client.recv(1024)
print(data.decode())
client.close()

image
image

image

posted @ 2022-01-18 20:59  一览如画  阅读(39)  评论(0)    收藏  举报