python学习日志--day10

时间:2021-02-28 22:39:16

一、笔记

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.')

输出结果

python学习日志--day10


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()

输出结果

python学习日志--day10


进程间通信(不同进程间内存是不共享的

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()

输出结果

python学习日志--day10


进程池

  • 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()

输出结果

python学习日志--day10


协程(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()

输出结果

python学习日志--day10



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-print
    gevent.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),])

输出结果

python学习日志--day10

简单的网页爬虫


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")

输出结果


python学习日志--day10

生成的文件

python学习日志--day10


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()