查看进程号
from multiprocessing import Process,current_process
import os
current_process().pid #查看当前进程号
os.getpid() #查看当前进程号
os.getppid() #查看当前进程的父进程号
僵尸进程与孤儿进程
'''
僵尸进程:进程结束后不会立即释放占用的资源(PID),会保留一段时间供父进程查看
孤儿进程:子进程存活,父进程意外死亡,孤儿进程操作系统会自动回收相应的资源
'''
守护进程
'''
被守护进程结束后守护进程也立即跟着结束
'''
#如何开启 在start语句之前写一下代码
p.daemon=True
p.start()
互斥锁
'''
多个人在操作同一份数据的时候会出现数据错乱问题
针对上述问题我们通常都是加锁处理
作用:
将并发变成串行,牺牲了程度的运行效率但是保证了数据的安全
注意:
只在操作数据的部分加锁即可
锁尽量不要着急去处理,容易造成死锁现象
'''
from multiprocessing import Lock
mutex=Lock()
#抢锁
mutex.acquire()
#释放锁
mutex.release()
#模拟抢票
队列Queue
'''
队列:先进先出
堆栈:先进后出
'''
from multiprocessing import Queue
q=Queue() #括号内可以放数字来限制队列的大小
q.put() #放数据
q.get() #取数据
q.full() #判断队列是否满了
q.empty() #判断队列是否空了
q.get_nowait() #取数据的时候如果没有数据直接报错
q.get(timeout=3) #取数据的时候如果没有数据等3秒,还没有则直接报错
进程间通信
'''
进程间无法直接进行数据交互,但是可以通过队列或者管道实现数据交互
管道:
队列:管道+锁
本地测试是才会用到Queue,实际生产则用别人封装好的功能
redis
kafka
RQ
'''
生产者与消费者模型
'''
生产者+消费队列+消费者
为何要有消息队列的存在:是为了解决供销不平衡的问题
#JoinableQueue
可以被等待的q
你在我往队列中放数据的时候,内部会有一个计数器自动加1
你在从队列中取数据的时候,调用task_done()内部计时器自动减1
q.join()当计数器为0是才继续往下执行
'''
线程理论
'''
进程:资源单位
线程:执行单位
线程才是真正干活的人,干活的过程中需要的资源由所在的进程提供
每一个进程都自带一个线程
同一个进程内可以创建多个线程
开进程
申请内存空间
“拷贝代码”
消耗资源较大
开线程
同一个进程内创建多个线程,无需上述两部操作,消耗资源相对较小
'''
开启进程的两种方式
# 方式一
from multiprocessing import Process
from threading import Thread
import time
def task(name):
print('%s is running'%(name))
time.sleep(2)
print('%s is over'%(name))
if __name__ == '__main__':
t=Thread(target=task,args=('lz',))
t.start()
# p = Process(target=task,args=('lz1',))
# p.start()
print('主')
#方式二
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name):
#重写了别人的方法,有不知道别人的方法有什么
super().__init__()
self.name=name
def run(self) :
print('%s is running'%(self.name))
time.sleep(1)
print('%s is over'%(self.name))
if __name__ == '__main__':
t=MyThread('lz')
t.start()
print('主')
TCP服务端实现并发的效果
import socket
from threading import Thread
from multiprocessing import Process
'''
服务端
1、要有固定的IP和PORT
2、不间断提供服务
3、能够支持并发
'''
server=socket.socket()#括号内不加参数默认就是tcp协议
server.bind(('127.0.0.1',8081))
server.listen(5)
def task(conn):
while True:
try:
data=conn.recv(1024)
if len(data)==0:break
print(data.decode('utf-8'))
conn.send(data.upper())
except Exception as e:
print(e)
break
conn.close()
while True:
conn,addr=server.accept()
#通信循环
t=Thread(target=task,args=(conn,))
t.start()
'''
客户端
'''
import socket
client=socket.socket()
client.connect(('127.0.0.1',8081))
while True:
data=input('>>>>:').strip()
client.send(data.encode('utf-8'))
data1=client.recv(1024)
print(data1.decode('utf-8'))
进程对象的join方法
from threading import Thread
import time
def task(name):
print('%s is running'%(name))
time.sleep(1)
print('%s is over'%(name))
if __name__ == '__main__':
t = Thread(target=task,args=('lz',))
t.start()
t.join() #主进程等待子进程运行结束再执行
print('主')
同一个进程下多个线程的数据共享
from threading import Thread
# from multiprocessing import Process
import time
money=100
def task():
global money
money=666
if __name__ == '__main__':
t= Thread(target=task)
# p = Process(target=task)
# p.start()
t.start()
print(money)
线程对象属性及其他方法
from threading import Thread,active_count,current_thread
import os,time
def task(n):
print('hello world',current_thread().name)
time.sleep(n)
if __name__ == '__main__':
t = Thread(target=task,args=(1,))
t1 = Thread(target=task,args=(2,))
t.start()
t1.start()
t1.join()
print('主',active_count()) #统计当前正在活跃的线程数
# print('主',os.getpid())
# print('主',current_thread().name) #获取线程名字
守护线程
from threading import Thread
import time
def task(name):
print('%s is running' % (name))
time.sleep(1)
print('%s is over' % (name))
if __name__ == '__main__':
t = Thread(target=task, args=('lz',))
t.daemon = True
t.start()
print('主')
线程互斥锁
from threading import Thread,Lock
import time
money = 100
mutex=Lock()
def task():
global money
mutex.acquire()
tmp = money
time.sleep(0.1)
money = tmp - 1
mutex.release()
if __name__ == '__main__':
t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(money)
GIL全局解释器锁
'''
重点:
1、GIL不是python的特点而是CPython解释器的特点
2、GIL是保证解释器级别的数据的安全
3、GIL会导致同一个进程下的多个线程无法同时执行即无法利用多核优势
4、针对不同的数据还是需要加不同的锁处理
5、解释型语言的通病:同一个进程下多个线程无法利用多核优势
'''
GIL与普通互斥锁的区别
from threading import Thread,Lock
import time
money = 100
mutex=Lock()
def task():
global money
mutex.acquire()
tmp = money
time.sleep(0.1)
money = tmp - 1
mutex.release()
if __name__ == '__main__':
t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(money)
同一个进程下的多线程无法利用多核优势
#计算密集型
# from multiprocessing import Process
# from threading import Thread
# import os,time
# def work():
# res = 0
# for i in range(1000000):
# res *= i
#
# if __name__ == '__main__':
# l = []
# print(os.cpu_count())
# start_time=time.time()
# for i in range(8):
# p = Process(target=work)
# t = Thread(target=work)
# t.start()
# # p.start()
# l.append(t)
# for p in l:
# p.join()
# print(time.time()-start_time) #0.9109606742858887
#IO密集型
from multiprocessing import Process
from threading import Thread
import os,time
def work():
time.sleep(2)
if __name__ == '__main__':
l = []
print(os.cpu_count())
start_time=time.time()
for i in range(40):
p = Process(target=work) #4.8199303150177
t = Thread(target=work) #2.01092791557312
t.start()
# p.start()
# l.append(p)
l.append(t)
for p in l:
p.join()
print(time.time()-start_time)
'''
总结:
多进程和多线程都各有各自的优势
通常用多进程下开设多线程
'''