目录
- 进程
- 线程
进程
1.进程互斥锁
异步可以让多个任务在几个进程中并发处理,他们之间没有运行顺序,一旦开启也不受我们的控制,尽管并发编程让我们更加充分的利用IO资源,但是当多个进程使用同一份资源的时候,就会引发数据安全或顺序混乱的问题
import json
import time
from multiprocessing import Process
from multiprocessing import Lock
# 查看余票
def search(user):
# 打开data文件查看余票
with open('data.txt', 'r', encoding='utf-8') as f:
dic = json.load(f)
print(f'用户{user}查看余票,还剩{dic.get("ticket_num")}...')
# 开始抢票
def buy(user):
# 先打开获取车票数据
with open('data.txt', 'r', encoding='utf-8') as f:
dic = json.load(f)
# 模拟网络延时
time.sleep(1)
# 若有票,修改data数据
if dic.get("ticket_num") > 0:
dic['ticket_num'] -= 1
with open('data.txt', 'w', encoding='utf-8') as f:
json.dump(dic, f)
print(f'用户: {user}抢票成功!')
else:
print(f'用户: {user}抢票失败!')
# 开始抢票
def run(user, mutex):
# 并发: 异步执行
search(user)
# 串行: 同步执行
mutex.acquire()
buy(user)
mutex.release()
if __name__ == '__main__':
# 调用Lock()类得到一个锁对象
mutex = Lock()
# 同时来10个用户抢票
for i in range(10):
# 并发开启10个子进程
p = Process(target=run, args=(f'用户{i}', mutex))
p.start()
2.队列
1.队列的概念
创建一个共享的进程队列,可以使用Queue实现对进程之间的数据传递。
2.队列的使用方法
from multiprocessing import Queue
# 调用队列类,实例化队列对象
q = Queue(5) # 5指的是队列中可以存放五个参数,如果不穿参,可以放无限个参数,前提是硬件能跟得上
# 添加队列
q.put(1) # 变量1传入队列中,如果队列已经添加满了,就会卡住
# 判断队列是否位空
print(q.empty()) # 返回位True为空,False不为空
# 取出队列
print(q.get()) # 获取数据遵循‘先进先出’,若队列中无数据可取,也会卡住
# 取数据时不卡住
print(q.get_nowait()) # 没有数据的时候会报错。
# 查看队列是否满了
print(q.full()) # 满了为True,没有满位False
3.进程之间的通信
进程之间的数据是相互隔离的,要想实现进程间的通信(IPC),可以使用multiprocessing模块中的队列和管道,这两种方法是可以实现进程间数据传输的,由于队列是管道+锁的方式实现的,所以我们着重研究队列。
from multiprocessing import Process,Queue
def producer(q):
q.put('hello big baby')
def consumer(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p = Process(target=producer,args=(q,))
p1 = Process(target=consumer,args=(q,))
p.start()
p1.start()
# 输出为 hello big baby
4.生产者与消费者
生产者:生产数据的
消费者:消费数据的
线程
1.什么是线程
线程与进程都是虚拟单位,目的是为了更好的描述某种事物
进程:资源单位
线程:执行单位
开启一个进程,一定会有一个线程,线程才是真正的执行者,
2.为什么要使用线程
为了节省内存资源
开启进程会发生的两件事情:
1.开辟一个名称空间,每开启一个进程空间,都会占用一份内存资源,
2.会自带一个线程,
开启线程:
1.一个进程可以开启多个线程,
2.线程的开销远小于进程
注意:线程不能实现并行,线程只能实现并发,进程可以实现并行。
3.线程两种创建方式
进程不能直接在import下直接调用,线程可以。
# 开启线程方式1:
from threading import Thread
import time
def task():
print('线程开启')
time.sleep(1)
print('线程结束')
if __name__ == '__main__':
t = Thread()
t = Thread(target=task)
t.start()
print('主')
# 开启线程方式2:
from threading import Thread
import time
class Sayhi(Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
time.sleep(2)
print(self.name)
if __name__ == '__main__':
t = Sayhi('wang')
t.start()
print('主')
内存就像一个工厂,子进程就像一个工厂车间,线程就像车间内的流水线
4.线程对象的属性
线程之间的数据是共享的
5.守护线程
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行结束完毕之后被销毁,需要强调的是运行完毕并非终止运行
from threading import Thread
import time
def say(name):
time.sleep(1)
print(name)
if __name__ == '__main__':
t = Thread(target=say,args=('wang',))
t.setDaemon(True)
t.start()
print('主进程')
print(t.is_alive())
6.线程互斥锁
from threading import Thread, Lock
import time
mutex = Lock()
n = 100
def task(i):
print(f'线程{i}启动...')
global n
# mutex.acquire()
temp = n
time.sleep(0.1) # 一共等待10秒
n = temp-1
print(n)
# mutex.release()
if __name__ == '__main__':
t_l=[]
for i in range(100):
t = Thread(target=task, args=(i, ))
t_l.append(t)
t.start()
for t in t_l:
t.join()
# 100个线程都是在100-1
print(n)
原文地址:https://www.cnblogs.com/whkzm/p/11722083.html
时间: 2024-10-29 12:42:14