16.并发编程2

线程理论

1 什么是线程
进程其实一个资源单位(开启一个内存空间,里面放应该执行的代码,代码运行产生的数据),
而进程内的线程才是cpu上的执行单位
进程是资源单位 qq资源 相当于一个车间 造发动机和造轮胎能共享吗
线程其实指的就是代码的执行过程(开空间没关系,数据往进程去要)
线程就是车间流水线 跟车间要
至少有一个线程 一个车间也可以有多少流水线
2 为何要用线程
线程vs进程
1. 同一进程下的多个线程共享该进程内的资源
2. 创建线程的开销要远远小于进程
并发2种
多进程实际上是每个进程里面单独一个线程
由于进程当中资源不共享
并发多个任务需要通信需要利用管道或者队列
多线程是指同一个进程里面多个线程
本身同一个进程里面多个线程资源就共享
所以不需要借助任何的机制,数据之间就可以交互
3 如何用线程

from  threading import Thread
def task(name):
print('%s is running'%name)
time.sleep(2)
print('%s is done'%name)

if __name__ == '__main__':
    t = Thread(target=task,args=('线程1',))
    # 造线程非常快,因为不用开辟空间了
    t.start()
    print('主')

守护线程

主线程掌管了这个进程里面的资源
主线程不会死了,资源是来自主线程的
主线程是这个进程里面的老大
等待所有的子线程死了才死
车间里面的厂长,员工下班了他才下班

from  threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print('end123')

def bar():
    print(456)
    time.sleep(3)
    print('end456')

if __name__ == '__main__':
    # 线程
    t1 = Thread(target=foo)
    t2 = Thread(target=bar)
    #开启t1守护线程
    t1.daemon = True
    # # 造线程非常快,因为不用开辟空间了
    t1.start()
    t2.start()
    print('主')
    
因为456线程没有死掉
守护线程 》》主线程 》》非守护线程
按时下班的员工》》老板 》》加班的员工

多进程和多线程的应用场景

计算密集型:应该使用多进程,运行速度更快
IO密集型: 应该开启多线程,运行速度更快

线程自定义互斥锁

from threading import Thread,Lock
import time
mutex = Lock()
n = 100
def task():
    global n
    # 线程1加锁
    mutex.acquire()
    temp = n
    # 在这个时间消耗完之前,后面的99个线程都进来了
    # 并且拿到的是temp=100
    # 效率高了,不安全
    # IO操作切换线程
    time.sleep(0.1)
    n = temp - 1
    # 线程1计算完成释放锁
    mutex.release()
if __name__ == '__main__':
    t_l = []
    start = time.time()
    for i in range(100):
        t = Thread(target=task)
        t_l.append(t)
        t.start()
    for t in t_l:
        t.join()
    print(n,time.time()-start)

GIL锁

一、什么是GIL(全局解释器锁)
互斥锁就是把多个任务的共享数据的修改由并发变成串行
代码运行先拿到cpu的权限,还需要把代码丢给解释器,再在进程里面的线程运行
GIL本质就是一把互斥锁,相当于执行权限
每个进程内都会存在一把GIL,同一进程内的多个线程
必须抢到GIL之后才能使用解释器来执行自己的代码,
即同一进程下的多个线程无法实现并行,
用不了多核(多个cpu)优势
但是可以实现并发
因为多线程是遇到io操作就会释放GIL锁
二、为何要有GIL
垃圾回收机制不是线程安全的
每个进程内都会存在一把GIL
意味着有锁才能计算
多进程适合处理计算密集型
多线程适合处理io密集型 所以多线程多核优势没有意义
三、如何用GIL
有了GIL,应该如何处理并发

from  threading import  Thread
import time
def task(name):
    print('%s is running'%name)
    time.sleep(2)
if __name__ == '__main__':
    t1 = Thread(target=task,args=('线程1',))
    t2 = Thread(target=task,args=('线程2',))
    t3 = Thread(target=task,args=('线程3',))
    # 造线程非常快,因为不用开辟空间了
    t1.start()
    t2.start()
    t3.start()

基于tcp协议的套接字(链接循环+通讯循环版本+并发)

tcpsockserver服务器

class MyTCPhanler(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                data = self.request.recv(1024)
                print('收到客户端数据', data)

                # 变大写发送回去
                self.request.send(data.upper())
            except ConnectionResetError:
                break
if __name__ == '__main__':
    # 通信循环
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8081),MyTCPhanler)
    # 链接循环
    server.serve_forever()

服务端
客户端关闭了服务端会正常结束
服务端必须满足至少三点:
一、绑定一个固定的ip和port
二、一直对外提供服务,稳定运行
三、能够支持并发,因为是io密集型要开多线程

import socket
from  threading import Thread
def communicate(conn):
    # 通信循环
    while True:
        try:
            data = conn.recv(1024)
            print('收到客户端数据', data)

            # 变大写发送回去
            conn.send(data.upper())
        except ConnectionResetError:
            break
            
def server(ip,port,backlog=5):
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind((ip,port))
    server.listen(backlog)
    while True:
        # 链接循环
        conn,client_addr = server.accept()
        # 通信循环
        t = Thread(target=communicate,args=(conn,))
        t.start()

if __name__ == '__main__':
    s = Thread(target=server,args=('127.0.0.1',8081))
    s.start()

客户端

import socket
# 1买手机
# AF_INET 互联网协议
# SOCK_STREAM TCP流式协议,
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# print(phone)

# 2.拨号
# # 建立三次握手
phone.connect(('127.0.0.1',8081))

# 3.发/收消息
# 必须传入二进制,
# 物理层
while True:
    msg = input('>>>').strip()
    if len(msg)==0:continue
    phone.send(msg.encode('utf-8'))
    # 收
    data = phone.recv(1024)
    print('收到服务端数据',data)

# 4关机
phone.close()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值