zoukankan      html  css  js  c++  java
  • 疫情环境下的网络学习笔记 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密集型

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

  • 相关阅读:
    Django 的简单ajax
    django 模板语言的注释操作
    Django 使用Paginator分页
    Django 使用allauth报错
    selenium登录 京东滑动验证码
    The usage of Markdown---表格
    The usage of Markdown---引用
    The usage of Markdown---代码块
    The usage of Markdown---目录
    The usage of Markdown---链接的使用
  • 原文地址:https://www.cnblogs.com/telecasterfanclub/p/12769472.html
Copyright © 2011-2022 走看看