'''
from mutiprocessing import Proces
1、实例化产生对象
2、类的继承,run方法
ps:
在windows里面开启进程代码一定要写在main代码块内
创建一个进程就是申请一个内存空间将代码丢进去
'''
第一种方式:
from multiprocessing import Process
import time
deftask(name):print('%s is running'%name)
time.sleep(3)print('%s is over'%name)if __name__ =='__main__':#1、创建一个对象
p = Process(target=task,args=('jason',))#容器类型哪怕里面只有一个元素,建议要用逗号隔开#2、开启进程
p.start()#告诉操作系统帮你创建一个进程print('主')#代表程序执行完毕#第二种方式from multiprocessing import Process
import time
classMyProcess(Process):defrun(self)->None:print('hello bf girl')
time.sleep(1)print('get out!')if __name__ =='__main__':
p = MyProcess()
p.start()print('主')
开进程和开线程的步骤基本都是一样的,只是导入模块不一样
类的对象调用方法
类的继承重写run方法
第一种方法:
from multiprocessing import Process
from threading import Thread
import time
deftask(name):print('%s is running'%name)
time.sleep(1)print('%s is over')#开启线程不需要在main下执行代码,直接书写就可以#但是我们还是习惯性的将启动命令卸载main下面
t = Thread(target=task(),args=('egon',))
t.start()#创建线程的开销非常小,创建的非常快print('主')
第二种方法:
from multiprocessing import Process
from threading import Thread
import time
classMythead(Thread):def__init__(self,name):'''针对给类里面的参数传参需定义一个init方法'''#重写了别人的方法 又不知道别人的方法里有啥 就调用父类的方法super().__init__()
self.name = name
defrun(self)->None:print('%s is running'%self.name)
time.sleep(1)print('egon')#开启线程不需要在main下执行代码,直接书写就可以#但是我们还是习惯性的将启动命令卸载main下面if __name__ =='__main__':
t = Mythead
t.start()print('主')
TCP服务端实现并发的效果
服务端:
import socket
from threading import Thread
from multiprocessing import Process
deftalk(conn):# 通信循环whileTrue:try:
data = conn.recv(1024)iflen(data)==0:breakprint(data.decode('utf-8'))
conn.send(data.upper())except ConnectionResetError as e:print(e)break
conn.close()# 连接循环defserver(ip, port):
server = socket.socket()# 括号不加参数默认TCP
server.bind(('127.0.0.1',8081))
server.listen(5)whileTrue:
conn, addr = server.accept()
t = Thread(target=talk, args=(conn,))# t = Process(target=talk, args=(conn,)) #开启进程
t.start()if __name__ =='__main__':
s = Thread(target=server, args=('127.0.0.1',8080))
s.start()
客户端:
import socket
client = socket.socket()
client.connect(('127.0.0.1',8081))whileTrue:
client.send(b'hello world')
data = client.recv(1024)print(data.decode('utf-8'))
线程对象的join方法
import ntpath
import stat
from threading import Thread
import time
deftask(name):print('')if __name__ =='__main__':
p = Thread(target=task, args=('engon',))
p.start()
p.join()#主线程等待子进程结束后执行print('主')
线程间数据共享
import ntpath
import stat
from threading import Thread
import time
money =100deftask():global money
money =666print(money)if __name__ =='__main__':
t = Thread(target=task,)
t.start()
t.join()print(money)
import time
from threading import Thread,Lock
mutex = Lock()
money =100deftask():global money
mutex.acquire()#上锁
tmp = money
time.sleep(0.1)#睡一下会释放GIL锁
money = tmp -1
mutex.release()if __name__ =='__main__':
t_list =[]for i inrange(100):
t = Thread(target=task)
t.start()
t_list.append(t)for t in t_list:
t.join()print(money)'''
100个线程骑起来之后 要先去抢GIL
我进入io GIL会自动释放,但我手上还有一个自己的互斥锁
其他线程虽然抢到了GIL但是抢不到互斥锁
最终GIL还是回到你的手上,你再去操作数据
'''
同一个进程下的多线程无法利用多核又是,是不是就没有用了
'''
多线程是否有用要看具体情况
单核:四个任务(IO密集型\计算密集型)
多核:四个任务(IO密集型\计算密集型)
'''#计算密集型 每个任务都需要10s
单核(不用考虑,现在都是多核):
多进程:额外的消耗资源
多线程:减少开销
多核:
多进程:假设4个任务,四个cpu同时帮忙算,总耗时10s+
多线程:总耗时 40s+ (一个进程下多线程无法利用多核优势)
#IO密集型 每个任务都需要10s,cpu基本不工作了,只是来回切换,线程和进程都无法利用多核优势
多核:
多进程:相对浪费资源
多线程:更加节省资源
计算密集型举例:
#计算密集型from multiprocessing import Process
from threading import Thread
import os,time
defwork():
res =1for i inrange(1,100000):
res *= i
if __name__ =='__main__':
l =[]print(os.cpu_count())#获取当前计算机CPU个数
start_time = time.time()for i inrange(4):
p = Process(target=work)#5.4251203536987305
t = Thread(target=work)#10.328745126724243# p.start()# l.append(p)
t.start()
l.append(t)for p in l:
p.join()print(time.time()-start_time)#多进程胜出
IO密集型距离:
#IO密集型from multiprocessing import Process
from threading import Thread
import os,time
defwork():
time.sleep(2)if __name__ =='__main__':
l =[]print(os.cpu_count())#获取当前计算机CPU个数
start_time = time.time()for i inrange(40):
p = Process(target=work)#2.947589159011841
t = Thread(target=work)#2.0187268257141113# p.start()# l.append(p)
t.start()
l.append(t)for p in l:
p.join()print(time.time()-start_time)#多线程胜出
总结:
'''
多进程和多线程都有各自的优势,我们通常可以再多进程下面开设多线程,这样既可以利用多核,也可以减少资源消耗
'''
线程池:
"""
回顾之前TCP并发是通过每来一个人就开设一个进程或者线程去处理
""""""
无论开设进程也好,还是开设线程也好 都是需要消耗资源
只不过开设线程比开设进程的稍微小一点而已
我们是不可能做到无限制的开设进程和线程的 因为计算机硬件的资源更不上!!
硬件开发的速度远远赶不上软件
我们的宗旨是在保证计算机硬件能正常工作的情况下最大限度利用它
"""# 池的概念"""
什么是池?
池是用来保证计算机硬件安全的情况下最大限度的利用计算机
他降低了程序的运行效率但保证了计算机硬件的安全,从而让写的程序正常运行
"""# 基本使用:from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
pool = ThreadPoolExecutor()# 括号内可以传数字 不传的花默认会开设当前计算机cpu个数五倍的线程"""
池子造出来之后 里面会固定存五个线程
这五个线程不会出现重复创建和销毁
池子的使用:
只需要将做的任务往池子中提交就好,自动会有人来服务
"""deftask(n):print(n)
time.sleep(0.5)return'asd'"""
任务的提交方式
同步:提交之后等待返回结果在往下执行
异步:提交之后不等待返回结果,执行完直接往下执行
如何获取返回结果?
"""# pool.submit(task, 1) # 朝池子中提交任务 异步提交# print('主')
t_list =[]for i inrange(20):# 朝池子中提交20个任务
res = pool.submit(task, i)# <Future at 0x1fb8c2510a0 state=pending># print(res)# print(res.result()) # result方法:1、同步提交类似join 2、打印返回task的结果
t_list.append(res)# 等待线程池中所有任务执行完毕之后再继续往下执行
pool.shutdown()# 关闭线程池 等待线程池中所有的任务运行完毕for t in t_list:print('>>>:', t.result())# 结果是有序的
进程池:
# 基本使用:from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time
import os
pool = ProcessPoolExecutor()# 括号内可以传数字 不传的花默认会开设当前计算机cpu个数进程"""
池子造出来之后 里面会固定存五个进程
这五个进程不会出现重复创建和销毁
池子的使用:
只需要将做的任务往池子中提交就好,自动会有人来服务
"""deftask(n):print(n, os.getpid())
time.sleep(0.5)return'asd'defcall_back(n):print('call_back', n.result())"""
任务的提交方式
同步:提交之后等待返回结果在往下执行
异步:提交之后不等待返回结果,执行完直接往下执行
如何获取返回结果?
异步提交任务返回结果 应该通过回调机制来获取
回调机制
就相当于给每个异步任务绑定了一个定时炸弹
一旦该任务有结果立刻触发爆炸
"""if __name__ =='__main__':# pool.submit(task, 1) # 朝池子中提交任务 异步提交# print('主')
t_list =[]for i inrange(20):# 朝池子中提交20个任务
res = pool.submit(task, i).add_done_callback(call_back)
t_list.append(res)
总结:
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
pool = ProcessPoolExecutor()#创建进程池
pool = ThreadPoolExecutor()#线程创建池
res =pool.submit(task, i)#submit会返回一个future类的对象,该对象调用result就能获取到任务的结果
异步回调机制:
给每一个异步提交的任务绑定一个方法,一旦任务有结果了会立刻自动触发该方法
defcall_back(n):print('call_back', n.result())
res =pool.submit(task, i).add_done_callback(call_back)#注意异步回调函数拿到的是一个对象,也需要result才能拿到结果
协程基本原理(了解)
进程:资源单位
线程:执行单位
协程:单进程下实现并发,一个并不是实际存在的东西
我们程序员自己在代码层面上检测我们所有io操作
一旦遇到io了,我们在代码级别完成切换
这样给cpu的感觉是你这个程序一致运行,没有IO
从而提升程序的运行效率
多道技术
切换+保存状态
cpu两种切换
1、程序遇到io
2、程序长时间占用
代码如何做到
切换+保存状态 (yield)
#保存上次我执行的状态 下一次接着上一次的操作继续往后执行#切换不一定是提升效率,也有可能是降低效率,IO切提升效率,没有IO切降低效率
验证切换是否一定提升效率:
import time
# def func1():# for i in range(100000000):# i+1### def func2():# for i in range(100000000):# i+1deffunc1():whileTrue:100000000+1yielddeffunc2():
g = func1()# 初始化生成器for i inrange(100000000):
i +1next(g)
start_time = time.time()
func1()
func2()print(time.time()- start_time)
genvet模块
from gevent import monkey;monkey.patch_all()import time
from gevent import spawn #检测机制"""
genvet监测io
gevent模块本身无法检测常见的一些io操作
apawn在检测的时候是异步的
需要再使用的时候额外的导入一句话
from gevent import monkey
monkey.patch_all()
又由于上面两句话在使用gevent模块的时候肯定要导入,所以还支持简写
from gevent import monkey;monkey.patch_all()
"""defheng():print('哼')
time.sleep(2)print('哼')defha():print('哈')
time.sleep(3)print('哈')
start_time = time.time()
g1 = spawn(heng)
g2 = spawn(ha)
g1.join()
g2.join()#等待被检测的任务执行完毕,再往后执行print(start_time - time.time())
协程实现TCP服务端的并发
服务端:
from gevent import monkey;monkey.patch_all()import socket
from gevent import spawn
"""
不开启进程和线程实现 TCP服务端并发
"""import socket
defcommunication(conn):# 通信循环whileTrue:try:
data = conn.recv(1024)iflen(data)==0:breakprint(data.decode('utf-8'))
conn.send(data.upper())except ConnectionResetError as e:print(e)break
conn.close()# 连接循环defserver(ip, port):
server = socket.socket()# 括号不加参数默认TCP
server.bind(('127.0.0.1',8080))
server.listen(5)whileTrue:
conn, addr = server.accept()
spawn(communication, conn)if __name__ =='__main__':
g1 = spawn(server,'127.0.0.1',8080)
g1.join()
客户端:
from threading import Thread, current_thread
import socket
defxclient():
client = socket.socket()
client.connect(('127.0.0.1',8080))
n =0whileTrue:
msg ='%s say hello %s'%(current_thread().name, n)
n +=1
client.send(msg.encode('utf-8'))
data = client.recv(1024)print(data.decode('utf-8'))if __name__ =='__main__':for i inrange(50):
t = Thread(target=xclient)
t.start()
总结:
多进程下面开设多线程
多线程下面再利用协程
最大程度提升软件运行效率