疫情环境下的网络学习笔记 python 4.24

4.24

昨日回顾

  1. 进程对象其他方法

    from muliprocessing import Process,current_process
    import os 
    current_process().pid # 当前进程号
    os.getpid() # 当前进程号
    os.getppid() # 父进程号
    
  2. 僵尸进程:进程结束之后不会立刻释放占用的资源,会八六一段时间供父进程查看

    孤儿进程:父进程意外死亡,孤儿进程操作系统会自动回收相应资源

  3. 守护进程:在父进程结束之后立刻跟着结束

    p.daemon = True
    p.start()
    
  4. 互斥锁

    多个进程在操作同一份数据的时候可能出现数据错乱的问题,针对这个问题,通常加锁处理

    将并发变成串行,牺牲程序运行效率,但是保证了数据的安全

    可以从multiprocessing导入锁

    from multiprocessing import Lock
    mutex = Lock()
    # 抢锁
    mutex.acquire()
    # 进行操作
    # 释放锁
    mutex.release()
    
  5. 队列Queue

    from multiprocessing import Queue
    # 可以直接使用queue,也可以在multiprocessing里导入
    q = Queue(max_size) # 可以指定队列大小
    q.put(1) # 放数据,队列满了再放阻塞
    q.get() # 取数据,队列空了再取阻塞
    
    q.full()
    q.empty()
    q.get_nowait() # 取不到直接报错
    q.get(timeout = 5) # 等5s,取不到则报错
    
    
  6. 进程间通信

    进程与进程之间是无法直接进行数据交互的,可以通过队列或管道实现数据交互

    队列 = 管道+锁

    本地测试的时候才会用到Queue,实际生产用的都是别人封装好的:redis

  7. 生产者与消费者模型

    # 生产者+消息队列+消费者
    # JoinableQueue:可以被等待的,带有计数器的queue
    # 在往队列中放数据的时候,计数器自动+1,从队列中取数据的时候,调用task_done方法,计数器自动-1
    q.join() # 当计数器为0的时候才继续往下运行
    
  8. 线程

今日内容

  1. 开启线程的两种方式
  2. TCP服务端实现并发的效果
  3. 线程对象的join方法
  4. 线程间数据共享
  5. 线程对象属性及其他方法

开启进程的两种方式

threading模块

  1. 获得Thread对象
  2. 继承Thread类
# 第一种方式
from threading import Thread
import time
def task(name)
	print('%s running'%name)
	time.sleep(1)
	print('%s over'%s)
	
# 开启线程不需要在main下执行代码,直接书写就可以
# 但是还是习惯性地将启动命令写在main下面
t = Thread(target=task,args=('aaa',))
t.start()
# 创建线程的开销非常小,几乎代码一执行,就创建了
# 第二种方式
from threading import Thread
import time
class MyThread(Thread):
	def __init__(self,name):
		super().__init__()
		self.name = name
		
	def run(self):
		print('%s running'%name)
		time.sleep(1)
		print('%s over'%s)

if __name__ == '__main__':
	t = MyThread('aaa')
	t.start()
	print('主线程')

TCP服务端并发

服务端的需求

  1. 要有固定的IP和端口
  2. 24小时不间断
  3. 能够支持并发

服务端

server = socket.socket() # 不写参数,默认是TCP
server.bind(('127.0.0.1',8080))
server.listen(5)
	
# 将服务的代码单独封装成一个函数
def talk(conn):
	while True:
		try:
			data = conn.recv(1024)
			if len(data == 0):break
			print(data.decode('utf-8'))
		except Exception as e:
			print(e)
	conn.close()
	
# 连接循环,使用线程实现并发
while True:
	conn,addr = server.accept() # 自动阻塞
	# t.Process(target=talk,args=(conn,))
	t = Thread(target=talk,args=(conn,))
	t.start()

客户端

import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
	client.send(b'hello')
	data = client.recv(1024)
	print(data.decode('utf-8'))

补充decode,encode知识点

# 不想搞混decode和encode,可以使用str,bytes方法
# 都指定encoding为utf
data = str(data,encoding = 'utf-8')

线程对象的join方法

from threading import Thread
import time

def task(name)
	print('%s running'%name)
	time.sleep(1)
	print('%s over'%s)
	
if __name__ == '__main__':
	t = Thread(target=task,args=('aaa',))
	t.start()
	# 如果不加join,主线程在t结束之前就结束了
	t.join()
	# 等待t结束之后才会往下走
	print('主线程')

同一进程下的线程数据共享

与进程不同

线程对象及其他方法

from threading import Thread
import time,os
def task():
	print('hello',os.getpid(),current_thread().name)
	# 验证线程在同一个进程下,pid是一样的
	# Thread-1

if __name__ == '__main__':
	t = Thread(target=task)
	t.start()
	print('主进程',os.getpid(),current_thread().name)

守护线程

主线程结束之后,不会立刻结束,会等待所有其他非守护子线程结束才会结束

因为主线程的结束意味着所在的进程结束

使用方法一样是在start上面加daemon为True

t = Thread(target=task)
t.daemon = True
t.start()

线程互斥锁

from threading import Thread
from multiprocessing import Lock
import time,os

money = 100
def task():
	global money
	mutex.acquire()
	tmp = money
	time.sleep(1)
	money = tmp-1
	mutex.release()

if __name__ == '__main__':
	t_list = []
	mutex  = Lock()
	for i inrange(100):
		t = Thread(target=task)
		t.start()
		t_list.append(t)
	for t in _list:
		t.join()
	print(money)
	

GIL全局解释器锁

  1. GIL不是python的特点,而是Cpython解释器的特点
  2. Cpython种GIL是一把互斥锁,阻止一个进程下多个线程的同时执行
  3. Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行。虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行
  4. 保证解释器级别的数据的安全

上下文管理mutex

with mutex:
	tmp = money
	time.sleep(0.1)
	money = tmp - 1
# 自动抢锁,结束了自动释放锁

python同一进程下多线程是否没用

python同一进程下无法利用多核又是,是不是就没有用了

多线程是否有用要看具体情况:计算密集型任务,IO密集型任务

  • 计算密集型
  • IO密集型

多进程和多线程要结合使用

猜你喜欢

转载自www.cnblogs.com/telecasterfanclub/p/12769472.html