一、笔记
1、IO操作不占用cpu
2、计算占用cpu
3、python多线程,不适合cpu密集操作型的任务,适合IO操作密集型的任务
二、多进程(multiprocessing)
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print ('Run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__':
print ('Parent process %s.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print ('Process will start.')
p.start()
p.join()
print ('Process end.')
输出结果
from multiprocessing import Process
import os
def info(title):
print(title)
print('module name:', __name__)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print("\n\n")
def f(name):
info('\033[31;1mcalled from child process function f\033[0m')
print('hello', name)
if __name__ == '__main__':
info('\033[32;1mmain process line\033[0m')
p = Process(target=f, args=('bob',))
p.start()
输出结果
进程间通信(不同进程间内存是不共享的)
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # prints "[42, None, 'hello']"
p.join()
输出结果
进程池
- apply
- apply_async
from multiprocessing import Process, Pool,freeze_support
import time
import os
def Foo(i):
time.sleep(2)
print("in process",os.getpid())
return i + 100
def Bar(arg):
print('-->exec done:', arg,os.getpid())
if __name__ == '__main__':
#freeze_support()
pool = Pool(processes=3) #允许进程池同时放入5个进程
print("主进程",os.getpid())
for i in range(10):
pool.apply_async(func=Foo, args=(i,), callback=Bar) #callback=回调
#pool.apply(func=Foo, args=(i,)) #串行
#pool.apply_async(func=Foo, args=(i,)) #串行
print('end')
pool.close()
pool.join() #进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。.join()
输出结果
协程(Coroutine)--一种用户态的轻量级线程
定义:
- 必须在只有一个单线程里实现并发
- 修改共享数据不需加锁
- 用户程序里自己保存多个控制流的上下文栈
- 一个协程遇到IO 操作自动切换到其他协程
优点:
- 无需线程上下文切换的开销
- 无需原子操作锁定及同步的开销(原子操作:不会被线程调度机制打断的操作)
- 方便切换控制流,简化编程模型
- 高并发+高扩展+低成本
Greenlet
from greenlet import greenlet
def test1():
print(12)
gr2.switch()
print(34)
gr2.switch()
def test2():
print(56)
gr1.switch()
print(78)
gr1 = greenlet(test1) #启动一个携程
gr2 = greenlet(test2)
gr1.switch()
输出结果
Gevent
import gevent
def foo():
print('Running in foo') #切换bar-print
gevent.sleep(2) #切换
print('Explicit context switch to foo again')
def bar():
print('Explicit精确的 context内容 to bar') #切换到func3-printgevent.sleep(1)print('Implicit context switch back to bar')def func3(): print("running func3 ") #切换到foo-gevent,卡住;切换到bar-gevent,卡住,直接执行func3-geven,没卡住,func3-print2 gevent.sleep(0) print("running func3 again ")gevent.joinall([ gevent.spawn(foo), #生成, gevent.spawn(bar), gevent.spawn(func3),])输出结果
简单的网页爬虫
from urllib import request
def f(url):
print('GET: %s' % url)
resp = request.urlopen(url)
data = resp.read()
f = open("url.html","wb")
f.write(data)
f.close()
print('%d bytes received from %s.' % (len(data), url))
f("http://www.cnblogs.com/alex3714/articles/5248247.html")
输出结果
生成的文件
IO多路复用
- 虚拟空间分为:用户空间和内核空间
select解析socket通信
服务器端
import select
import socket
import queue
server = socket.socket()
server.bind(('localhost',9000))
server.listen(1000)
server.setblocking(False) #不阻塞
msg_dic = {}
inputs = [server,]
#inputs = [server,conn] #[conn,]
#inputs = [server,conn,conn2] #[conn2,]
outputs = [] #
#outputs = [r1,] #
while True:
readable ,writeable,exceptional= select.select(inputs, outputs, inputs )
print(readable,writeable,exceptional)
for r in readable:
if r is server: #代表来了一个新连接
conn,addr = server.accept()
print("来了个新连接",addr)
inputs.append(conn) #是因为这个新建立的连接还没发数据过来,现在就接收的话程序就报错了,
#所以要想实现这个客户端发数据来时server端能知道,就需要让select再监测这个conn
msg_dic[conn] = queue.Queue() #初始化一个队列,后面存要返回给这个客户端的数据
else: #conn2
data = r.recv(1024)
print("收到数据",data)
msg_dic[r].put(data)
outputs.append(r) #放入返回的连接队列里
# r.send(data)
# print("send done....")
for w in writeable: #要返回给客户端的连接列表
data_to_client = msg_dic[w].get()
w.send(data_to_client) #返回给客户端源数据
outputs.remove(w) #确保下次循环的时候writeable,不返回这个已经处理完的连接了
for e in exceptional:
if e in outputs:
outputs.remove(e)
inputs.remove(e)
del msg_dic[e]
客户端
import socket
HOST = 'localhost' # The remote host
PORT = 9001 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
msg = bytes(input(">>:"), encoding="utf8")
s.sendall(msg)
data = s.recv(1024)
#
print('Received', data)
s.close()