进程补充 | 线程
今日内容概要
- 僵尸进程余孤儿进程
- 守护进程
- 互斥锁
- 消息队列
- 实现进程间数据交互(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('主')
互斥锁
将并发编程串行,降低了效率,提高了数据安全性
使用锁注意事项:
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('没有票了!!!')
消息队列
打破进程间默认无法通信的情况
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('嘿嘿嘿!!!')
实现进程间数据交互(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()
生产者消费者模型
生产者:负责产生数据
消费者:负责处理数据
需要解决供需不平衡的现象
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() # 等待所有数据取干净
线程
线程:进程是一个资源单位,真正被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('主')
线程对象方法
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('主')
守护线程
"""
主线程结束代表整个进程结束,所以主线程需要等待所有费守护线程结束才可以结束
"""
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-------")
线程数据共享
from threading import Thread
m = 100
def index():
global m
m = 666
t = Thread(target=index)
t.start()
t.join()
print(m)
线程互斥锁
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)
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()