- 并行:真的多任务
并发:假的多任务
普通解释:
并发:交替做不同事情的能力
并行:同时做不同事情的能力
专业术语:
并发:不同的代码块交替执行
并行:不同的代码块同时执行
解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
例子:
- 顺序执行:你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
- 并发:你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
- 并行:你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并
线程
- 创建线程:
-
通过继承Thread类完成创建线程:
- 多线程共享全局变量(子线程与子线程,子线程与主线程,都共享):
-
多线程会资源竞争:
解决资源竞争:互斥锁 互斥锁的另一种锁法:
- 死锁:
-
多线程版udp聊天器(同时实现收和发)
做两个线程,一个while True收,一个while True发:
- 查看进程数:
进程
-
线程 vs 进程:
-
Queue:
通过Queue完成进程间通信: - 进程池:
-
多任务文件夹copy:
进度条实现:
协程
- 迭代器(一个拥有iter() 和 next() 的class类):
迭代器只在内存中保存生成数据的代码,用的时候随时调用,不需要存储大量数据
- 迭代逐一获取Classmate里的name: 上例把Classmate和ClassIterator合并也可以:
-
斐波那契
列表实现: 函数实现:
迭代器实现斐波那契:
生成器
函数中有yield语句的就是生成器,生成器可以让代码暂停执行,并保留结果,等到下一次next调用时再继续执行 上图打印结果:生成器实现斐波那契: 生成器的返回值:
-
send方式:
输出结果:
yield实现多任务(一般不使用yield): image.png -
gevent实现多任务(多任务一般都是使用gevent):
gevent遇到延时就会继续执行下一个任务
gevent实现多任务下载器:
-
返回固定页面的HTTP服务器:
import socket
import multiprocessing
import threading
# 协程
import gevent
from gevent import monkey
monkey.patch_all()
def service_client(new_socket):
request = new_socket.recv(1024)
print(request)
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
response += "hahaha"
new_socket.send(response.encode("utf-8"))
new_socket.close()
def main():
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置当服务器先close,即服务器端4次挥手之后资源能够立即释放,以保证下次运行程序时能立即执行
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server_socket.bind("", 7890)
tcp_server_socket.listen(128)
while True:
new_socket, client_addr = tcp_server_socket.accept()
# 简单web服务器实现
service_client(new_socket)
# 并发web服务器实现
p = multiprocessing.Process(target=service_client, args=(new_socket, ))
p.start()
new_socket.close()
# 并发web服务器实现 多线程实现
t = threading.Thread(target=service_client, args=(new_socket, ))
t.start()
# 并发web服务器实现 协程实现
gevent.spawn(service_client, new_socket)
tcp_server_socket.close()
if __name__ == '__main__':
main()
- 三次握手,四次挥手:
-
单进程,单线程,非堵塞实现并发:
accept 和 recv 都会堵塞
import socket
def main():
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.setblocking(False) # 设置套接字为非堵塞的方式
tcp_server_socket.bind("", 7890)
tcp_server_socket.listen(128)
client_socket_list = list()
while True:
try:
new_socket, new_addr = tcp_server_socket.accept()
except Exception as ret:
print("没有客户端连接")
else:
new_socket.setblocking(False) # 设置套接字为非堵塞的方式
client_socket_list.append(new_socket)
for client_socket in client_socket_list:
try:
recv_data = client_socket.recv(1024) # 如果client没有发送数据过来,这句会异常,进入except
except Exception as ret:
print("客户端没有数据传过来")
else:
if recv_data:
print("客户端传递了数据过来")
else: # 当client调用了close,会发送空数据过来,即recv_data为空
client_socket_list.remove(client_socket)
client_socket.close()
if __name__ == '__main__':
main()
- 长连接 短连接
-
epoll
epoll实现
网友评论