线程
线程是程序运行过程中,执行代码的分支
- 同步:事情一件件执行
- 异步:任务间的执行互不干扰,同时执行
- 并发:异步任务数大于通道数,随便找一个先走,一个个走,只是系统切换任务的速度很快,看起来像是一起运行
- 并行:异步任务数小于通道数,同时通过,是真的把所有人无一起执行
1.多任务
同一时间执行多个任务,就是多任务的概念,几核就同时运行几个任务,叫cpu的时间线轮转,
2.线程模块threading
Thread类
agrs=(tulpe);kwargs={‘参数名’:参数值}
Thread(group,target=,name,[args,kwarg])
- 1.创建线程,tread_name = threading.Thread(target = ,)
- 2.开始线程 tread_name.start()
函数里有*, 后面必须用关键字传参数
如果元组只有一个数字要加一个,(5,)
线程间执行互不干扰,创建线程是相对主线程来说的,创建的都是子线程
线程就是执行代码的分支,代码执行的最小单位,是真正干活的
3.获取活动线程的列表和个数
threading.enumerate() 获取活动线程列表
线程完成任务后会销毁
len(threading.enumerate) /threading.active_count()获取活动线程个数
当前线程:threading.current_thread()
4.注意点
1 . 线程的执行是无序的,就算按照一定顺序创建线程,但是他的执行是无序的
2 . 主线程等待所有子线程执行结束
exit()退出 return()退出函数
守护主线程:主线程结束强制结束子线程
1, 子线程 threading.Thread(,daemon= True)
2, 子线程设置 thread_name.setDaemon(True)
5.自定义线程类
继承threading.Thread封装相关的执行任务,重写run()
不需要用target指定执行某个任务,启动线程统一使用start(),start()里会调用run
如果要传参数,直接在自定义类里调用初始化方法 (def init(self,num1,num2)?,z再手动调用
如果子类提供了init方法,默认不会调用父类方法,需要手动调用父类init方法,才能使用那些父类的属性
( super(CustmThread,self).init() )
6.pycharm快捷注释多行:选中 + command + /
7.线程间可以共享全局变量,但是易出现资源竞争,互斥锁
全局变量加global原因,因为内存变量地址会改变,例如列表append不会改变,就不用加global ! 查看地址 id(变量)
共享全局变量会出现的
共享全局变量的都在取存,会发生疏忽误差
线程等待(同步),线程巩固,表示主线程等待第一个线程执行完,代码才能往下继续执行
多线程同时对全局资源的操作,有可能出现竞争
为了解决全局变量竞争,加入互斥锁
谁抢到这把锁,谁去执行,保证变量数据不发生错乱,对共享变量数据锁定,抱枕同一时刻只有一个访问变量
1.创建互斥锁,threading.Lock()
2.函数内调用锁, looc_name.acquire()
3.释放锁lock_name.release()
死锁
原因就是锁没有释放,或者搞了多个锁,解决办法就是提高代码逻辑,及时关闭锁
8.多线程的应用:
多线程的udp聊天器
一个线程收消息,一个发消息
主线程发,子线程收
多任务TCP服务器
阻塞的在服务的代码段创建子线程,就不影响主线程的进行,就能来一个客户端,并发服务
多任务TCP下载服务器
import os
import threading
import socket
import time
'''
客户端发来文件名,查找传送过去,阻塞的地方是等待发送给每个客户端信息
'''
def server(client_socket,client_addr):
# while True:
fil_name = client_socket.recv(1024) #阻塞
file_name = fil_name.decode('utf-8')
print(file_name)
#判断客户端又没有断开连接
if fil_name:
if os.path.exists(file_name):
with open(file_name,'rb') as f:
#读取了要发送的文件,开始发送
# print(send_data)
while True:
send_data = f.read(1024)
if send_data:
client_socket.send(send_data)
else:
break
else:
print('文件不存在:',file_name)
client_socket.send('null'.encode('utf-8'))
client_socket.close()
print('断开了连接',client_addr)
return
client_socket.close()
print('断开了连接',client_addr)
return
if __name__ == '__main__':
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEPORT,True)
server_socket.bind(('',7789))
server_socket.listen(128)
while True:
client_socket, client_addr= server_socket.accept()
print('客户端建立了连接',client_addr)
server_thread = threading.Thread(target=server,args=(client_socket,client_addr))
server_thread.start()
server_socket.close()
客户端
import threading
import socket
'''
输入文件名,找到文件
'''
def get_msg(client_socket):
file_name = input('输入文件名:')
client_socket.send(file_name.encode('utf-8'))
print('文件名传输成功')
buff = []
while True:
file_content = client_socket.recv(1024)#阻塞了
print('接收中。。。')
if file_content == 'null'.encode('utf-8'):
print('文件不存在')
return()
if file_content:
buff.append(file_content)
print('写入一次')
else:
break
data = b''.join(buff)
with open('拷贝'+file_name,'wb') as f:
f.write(data)
if __name__ == '__main__':
dest_ip = '192.168.16.62'
dest_port = 7789
client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client_socket.connect((dest_ip,dest_port))
print('连接成功')
get_msg(client_socket)
client_socket.close()