聊天室
server
from multiprocessing import Pool, cpu_count,Manager # 导入进程的manager对象
from multiprocessing.pool import ThreadPool
import socket
# 从队列中拿出数据,发给所有连接上的客户端
def send_data(dict_proxy, queue_proxy):
while True:
data = queue_proxy.get() # 从队列中拿出消息,发送给所有连接上来的客户端
print(data.decode())
for conn in dict_proxy.values(): # 去字典里拿对等连接套接字
conn.send(data)
# 处理客户端发来的信息
def worker_thread(connection, addr, dict_proxy, queue_proxy):
while True:
try:
recv_data = connection.recv(1024)
if recv_data:
data = "来自{addr} 的消息:{data}".format(addr=addr, data=recv_data.decode())
queue_proxy.put(data.encode()) # 把消息添加到到队列中
else:
raise Exception
except:
dict_proxy.pop(addr) # 从字典中删掉退出的客户端
data = '用户{}退出'.format(addr)
queue_proxy.put(data.encode()) # 把退出消息添加到队列中
connection.close()
break
# 处理 客户端建立连接 给客户端发送消息 客户端发来消息
def worker_process(server, dict_proxy, queue_proxy):
thread_pool = ThreadPool(cpu_count() * 2) # 通常分配2倍CPU个数的线程
# 把 向所有人发布客户端消息send_data 丢进进程池thread_pool
thread_pool.apply_async(send_data, args=(dict_proxy, queue_proxy))
while True:
conncetion, remote_address = server.accept() # 生成对等套接字
dict_proxy[remote_address] = conncetion # 把对等套接字加入字典中 保存起来
# dict_proxy.setdafault(remote_address,conncetion)
data = '用户{}登录'.format(remote_address)
queue_proxy.put(data.encode()) # 将用户登录消息添加到队列中
# 把 处理客户端消息worker_thread 丢进进程池thread_pool
thread_pool.apply_async(worker_thread, args=(conncetion, remote_address, dict_proxy, queue_proxy))
if __name__ == '__main__':
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(1000)
mgr = Manager()
dict_proxy = mgr.dict() # 用来保存连接上来的客户端,对等连接套接字 字典(哈希结构)对于数据的查找速度快
queue_proxy = mgr.Queue() # 把客户端发过来的消息通过队列传递 进程安全队列操作 mgr.Queue
n = cpu_count() # 打印当前电脑的cpu核数
process_pool = Pool(n)
for i in range(n): # 充分利用CPU,为每一个CPU分配一个进程
process_pool.apply_async(worker_process, args=(server, dict_proxy, queue_proxy)) # 把server丢到两个进程里面
process_pool.close()
process_pool.join()
client
import socket
import threading
def recv_data():
while True:
data = client.recv(1024)
print(data.decode())
client = socket.socket()
client.connect(('127.0.0.1', 8080))
# 开一个线程处理服务端随时发来的信息
thread = threading.Thread(target=recv_data, daemon=True)
thread.start()
# 接受输入
while True:
a = input('')
client.send(a.encode())
ssh://pyvip@127.0.0.1:1234/home/pyvip/.virtualenvs/py3env/bin/python3 -u /home/pyvip/py_case/server1.py
用户('127.0.0.1', 37576)连接
用户('127.0.0.1', 37578)连接
用户('127.0.0.1', 37580)连接
来自('127.0.0.1', 37580) 的消息:1
ssh://pyvip@127.0.0.1:1234/home/pyvip/.virtualenvs/py3env/bin/python3 -u /home/pyvip/py_case/client1.py
用户('127.0.0.1', 37576)连接
用户('127.0.0.1', 37578)连接
用户('127.0.0.1', 37580)连接
来自('127.0.0.1', 37580) 的消息:1
ssh://pyvip@127.0.0.1:1234/home/pyvip/.virtualenvs/py3env/bin/python3 -u /home/pyvip/py_case/client1.py
用户('127.0.0.1', 37578)连接
用户('127.0.0.1', 37580)连接
来自('127.0.0.1', 37580) 的消息:1
ssh://pyvip@127.0.0.1:1234/home/pyvip/.virtualenvs/py3env/bin/python3 -u /home/pyvip/py_case/client1.py
用户('127.0.0.1', 37580)连接
1
1
来自('127.0.0.1', 37580) 的消息:1
协程
yield
yield对象 返回这个对象 暂停这个函数 等待下次next重新激活
def fun():
yield 1 # 返回1 暂停函数
print('第一次执行')
yield 2 # 返回2 暂停函数
print('第二次执行')
a = fun()
print(a) # 生成器对象 但没有被执行
b = next(a) # next()调用 执行函数fun() 执行到yield时 暂停 并返回 1
print(b) # 输出1
<generator object fun at 0xb719883c>
1
def fun():
yield 1 # 返回1 暂停函数
print('第一次执行')
yield 2 # 返回2 暂停函数
print('第二次执行')
a = fun()
print(a) # 生成器对象 但没有被执行
b = next(a) # next()调用 执行函数fun() 执行到yield时 暂停 并返回 1
print(b) # 输出1
b = next(a) # 从上一次停止的地方继续执行 输出 第一次执行 并返回2
<generator object fun at 0xb726389c>
1
第一次执行
def fun():
yield 1 # 返回1 暂停函数
print('第一次执行')
yield 2 # 返回2 暂停函数
print('第二次执行')
a = fun()
print(a) # 生成器对象 但没有被执行
b = next(a) # next()调用 执行函数fun() 执行到yield时 暂停 并返回 1
print(b) # 输出1
b = next(a) # 从上一次停止的地方继续执行 输出 第一次执行 并返回2
print(b) # 输出2
<generator object fun at 0xb718989c>
1
第一次执行
2
def fun():
result = yield 1
print('result:',result)
print('第一次执行')
yield 2
print('第二次执行')
a = fun()
b = next(a)
print(b)
1
def fun():
result = yield 1
print('result:',result)
print('第一次执行')
yield 2
print('第二次执行')
a = fun()
b = next(a)
print(b)
next(a)
1
result: None
第一次执行
send 一个对象 激活生成器 执行生成器里面的代码 遇到yield回到调用位置
def fun():
result = yield 1
print('result:',result)
print('第一次执行')
yield 2
print('第二次执行')
a = fun()
b = next(a)
print(b)
# next(a)
a.send('你好') # 可以传值
1
result: 你好
第一次执行
next(a) 相当于 a.send(None)
def fun():
result = yield 1
print('result:',result)
print('第一次执行')
yield 2
print('第二次执行')
a = fun()
b = next(a) # 第一次
print(b)
next(a) # 第二次
a.send('你好') # 第三次 抛出StopIteration的异常 因后面没代码了
1
result: None
第一次执行
第二次执行
Traceback (most recent call last):
File "/home/pyvip/py_case/进阶/并发/协程/yield_test.py", line 13, in <module>
a.send('你好')
StopIteration
def fun():
while True:
result = yield 1
print('result:',result)
print('第一次执行')
yield 2
print('第二次执行')
a = fun()
b = next(a)
print(b)
next(a)
a.send('你好')
1
result: None
第一次执行
第二次执行
def fun():
i = 1
while True:
print(122)
print(i)
x = yield i
i = i + 1
print('第%d次执行fun函数:' % i)
print('x的值:', x)
a = fun()
next(a)
a.send('hello')
print('-' * 10)
a.send('python')
122
1
第2次执行fun函数:
x的值: hello
122
2
----------
第3次执行fun函数:
x的值: python
122
3
def fun():
i = 1
while True:
x = yield i
i = i + 1
print('第%d次执行fun函数:' % i)
print('x的值:', x)
a = fun()
next(a)
a.send('hello')
print('-' * 10)
a.send('python')
第2次执行fun函数:
x的值: hello
----------
第3次执行fun函数:
x的值: python
-
生产者 消费者模型
import random
import time
def produce(consum): # 生产者
next(consum)
while True:
item = random.randint(0, 99) # 随机产生一个0-99之间的数
print('生产者生产了', item)
consum.send(item) # 把item给消费者 切换到consumer()运行
time.sleep(1) # 每生产一个就休息一会 方便看数据
def consumer(): # 消费者
while True:
item = yield # 切换到produce()运行
print('消费者消费了', item)
c = consumer()
produce(c)
生产者生产了 83
消费者消费了 83
生产者生产了 99
消费者消费了 99
生产者生产了 79
消费者消费了 79
生产者生产了 27
消费者消费了 27
生产者生产了 97
消费者消费了 97
协程是在一个线程内的执行的,本质来说就是不同函数之间的切换调用。
对一个生成器必须要先next()让他执行到yield才能在send数据进去。
如果某一个协程被阻塞了,整个线程(进程)都被阻塞。任意时刻,只有一个协程在执行。