python 线程基础
线程基础
# 线程基础 """ 多任务的概念:就是操作系统可以同时运行多个任务 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已) 并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的 python的thread模块是比较底层的模块,python的threading是高级模块 常用操作 threading.currentThread(): 返回当前的线程变量。 threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程 threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果 run(): 用以表示线程活动的方法 start():启动线程活动 join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生 isAlive(): 返回线程是否活动的 getName(): 返回线程名 setName(): 设置线程名 线程注意点 使用threading模块时,往往会定义一个新的子类class,只要继承threading.Thread就可以了,然后重写run方法 当线程的run()方法结束时该线程完成。 多线程程序的执行顺序是不确定的 无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。 每个线程默认有一个名字,python会自动为线程指定一个名字 在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据 线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全) 如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确 同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。 可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B执行,再将结果给A;A再继续操作。 线程同步 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制 使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法 对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁 某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改; 直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。 互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。 hreading模块中定义了Lock类,可以方便的处理锁定 # 创建锁 mutex = threading.Lock() # 锁定 mutex.acquire() # 释放 mutex.release() 锁的好处 确保了某段关键代码只能由一个线程从头到尾完整地执行 锁的坏处 阻止了多线程并发执行 可能会造成死锁 死锁 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁 避免死锁 程序设计时要尽量避免(银行家算法) 添加超时时间等 """ # 多线程创建方式一 import threading # threading.Thread(target=函数) 传名称即可 def say(): print("你好啊,python") for i in range(5): t = threading.Thread(target=say) t.start() # 当调用start()时,才会真正的创建线程,并且开始执行 # 主线程会等待所有的子线程结束后才结束 import threading from time import sleep,ctime def sing(): for i in range(3): print("正在唱歌...%d" % i) sleep(1) def dance(): for i in range(3): print("正在跳舞...%d" % i) sleep(1) if __name__ == '__main__': print('---开始---:%s' % ctime()) t1 = threading.Thread(target=sing) t2 = threading.Thread(target=dance) t1.start() t2.start() sleep(5) # 屏蔽此行代码,试试看,程序是否会立马结束? print('---结束---:%s' % ctime()) # 查看线程数量 import threading from time import sleep,ctime def sing(): for i in range(3): print("正在唱歌...%d" % i) sleep(1) def dance(): for i in range(3): print("正在跳舞...%d" % i) sleep(1) if __name__ == '__main__': print('---开始---:%s' % ctime()) t1 = threading.Thread(target=sing) t2 = threading.Thread(target=dance) t1.start() t2.start() alength = threading.activeCount() print("活动线程数量是:%s" % alength) while True: # length = len(threading.enumerate()) # 返回一个包含正在运行的线程的list列表 # print('运行的线程数为:%d' % length) # if length <= 1: # break alength = threading.activeCount() print("活动线程数量是:%s" % alength) # 返回正在运行的线程数量 threading.activeCount() == len(threading.enumerate()) if alength <= 1: break sleep(0.5) # 线程的执行顺序 不能确定 import threading import time class MyThread(threading.Thread): def run(self): for i in range(3): time.sleep(1) msg = "I'm "+self.name+' @ '+str(i) print(msg) def test(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': test() # 线程执行代码的封装 import threading import time class MysThread(threading.Thread): def run(self): for i in range(3): time.sleep(1) msg = "I'm "+self.name+' @ '+str(i) # name属性中保存的是当前线程的名字 print(msg) if __name__ == '__main__': t = MysThread() t.start() # 多线程数据是共享的 from threading import Thread import time g_num = 100 def work1(): global g_num for i in range(3): g_num += 1 print("----in work1, g_num is %d---"%g_num) def work2(): global g_num print("----in work2, g_num is %d---"%g_num) print("---线程创建之前g_num is %d---"%g_num) t1 = Thread(target=work1) t1.start() # 延时一会,保证t1线程中的事情做完 time.sleep(1) t2 = Thread(target=work2) t2.start() # 互斥锁 -- 解决数据共享出现的问题 import threading import time g_num = 0 def test1(num): global g_num for i in range(num): mutex.acquire() # 上锁 g_num += 1 mutex.release() # 解锁 print("---test1---g_num=%d"%g_num) def test2(num): global g_num for i in range(num): mutex.acquire() # 上锁 g_num += 1 mutex.release() # 解锁 print("---test2---g_num=%d"%g_num) # 创建一个互斥锁 # 默认是未上锁的状态 mutex = threading.Lock() # 创建2个线程,让他们各自对g_num加1000000次 p1 = threading.Thread(target=test1, args=(1000000,)) p1.start() p2 = threading.Thread(target=test2, args=(1000000,)) p2.start() # 等待计算完成 while len(threading.enumerate()) != 1: time.sleep(1) print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num) # udp 聊天 import socket import threading # 接收信息 def recvs(udp_socket): while True: back = udp_socket.recvfrom(1024) msg = back print(msg) # 发送信息 def sends(udp_socket, dest_ip, dest_port): while True: msg = input("请输入你要发送的信息:") if msg == 'exit': break udp_socket.sendto(msg.encode(), (dest_ip, dest_port)) # udp主函数 def main(): udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) udp_socket.bind(('', 8001)) dest_ip = input("请输入对方的ip:") dest_port = int(input("请输入对方的port:")) t1 = threading.Thread(target=sends, args=(udp_socket, dest_ip, dest_port)) t2 = threading.Thread(target=recvs, args=(udp_socket,)) t1.start() t2.start() if __name__ == '__main__': main()