赞
踩
有很多的场景中的事情是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的
主线程会等到子线程执行结果之后主线程 才会结束
守护线程 不会等子线程结束 t.setDaemon(True)
等待子线程执行结束 主线程继续执行 t.join()
threading.enumerate() 查看当前线程的数量
线程运行是没有先后顺序的,但是先执行主线程再执行子线程
import threading import time def demo1(): for i in range(5): print("--test1--%d" % i) time.sleep(1) # break def demo2(): for i in range(10): print("--test2--%d" % i) time.sleep(1) def main(): t1 = threading.Thread(target=demo1) # 子线程1 t2 = threading.Thread(target=demo2) # 子线程2 t1.start() # 延时 # time.sleep(1) t2.start() # time.sleep(1) # 获取当前程序所有的线程 # 线程运行是没有先后顺序的 while True: print(threading.enumerate()) # 主线程 if len(threading.enumerate()) <= 1: break time.sleep(1) if __name__ == '__main__': main()
import threading import time def demo(): for i in range(5): print('demo') def main(): print(threading.enumerate()) # 不会创建线程 t1 = threading.Thread(target=demo) print(threading.enumerate()) # 创建线程 开始运行 t1.start() print(threading.enumerate()) if __name__ == '__main__': main()
import threading import time class A(threading.Thread): # def __init__(self): # super().__init__() def run(self): for i in range(5): print(i) def demo(self): for i in range(5): print(i) if __name__ == '__main__': t = A() t.start() t.demo() # 这种方式不是多线程的方式
在一个函数中,对全局变量进行修改的时候,是否要加global要看是否对全局变量的指向进行了修改,
如果修改了指向,那么必须使用global,
仅仅是修改了指向的空间中的数据,此时不用必须使用global
threading.Thread(target=test, args=(num,))
import threading import time num = [11, 22] # 多线程共享全局变量的!!! def demo1(num): num.append(33) print("demo1---%s" % str(num)) def demo2(num): print("demo2---%s" % str(num)) def main(): t1 = threading.Thread(target=demo1, args=(num, )) t2 = threading.Thread(target=demo2, args=(num, )) t1.start() # time.sleep(1) t2.start() # time.sleep(1) print("main---%s" % str(num)) if __name__ == '__main__': main()
import threading num = 0 def demo1(nums): global num for i in range(nums): num += 1 print('demo1 ---- num :%d' % num) def demo2(nums): global num for i in range(nums): num += 1 print('demo2 ---- num :%d' % num) def main(): t1 = threading.Thread(target=demo1, args=(10000000,)) t2 = threading.Thread(target=demo2, args=(10000000,)) t1.start() t2.start() print('main-----num:%d' % num) if __name__ == '__main__': main() 结果: main-----num :129389 demo2----num :11024590 demo1----num :11115370
字节码:
import dis
def add_sum(a):
a =+ 1
print(dis.dis(add_sum))
# 1 load a
# 2 load 1
# 3 执行add
# 4 赋值给a
某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定",其他线程不能改变,只到该线程释放资源,将资源的状态变成"非锁定",其他的线程才能再次锁定该资源。
互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
如果在上锁的之前已经上锁了,再上锁会阻塞,等到释放后在上锁
创建锁
mutex = threading.Lock()
锁定
mutex.acquire()
解锁
mutex.release()
import threading num = 0 # 创建吗一个互斥锁,默认是没有上锁的 mutex = threading.Lock() def demo1(nums): global num # 加锁 mutex.acquire() for i in range(nums): num += 1 # 解锁 mutex.release() print('demo1----num :%d' % num) def demo2(nums): global num # 加锁 mutex.acquire() for i in range(nums): num += 1 # 解锁 mutex.release() print('demo2----num :%d' % num) def main(): t1 = threading.Thread(target=demo1, args=(10000000,)) t2 = threading.Thread(target=demo2, args=(10000000,)) t1.start() t2.start() print('main-----num :%d' % num) if __name__ == '__main__': main() 结果: main-----num :188218 demo1----num :10000000 demo2----num :20000000
线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
RLock() 可重入的锁
import threading import time class MyThread1(threading.Thread): def run(self): # 对mutexA上锁 mutexA.acquire() # mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁 print(self.name+'----do1---up----') time.sleep(1) # 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了 mutexB.acquire() print(self.name+'----do1---down----') mutexB.release() # 对mutexA解锁 mutexA.release() class MyThread2(threading.Thread): def run(self): # 对mutexB上锁 mutexB.acquire() # mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁 print(self.name+'----do2---up----') time.sleep(1) # 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了 mutexA.acquire() print(self.name+'----do2---down----') mutexA.release() # 对mutexB解锁 mutexB.release() mutexA = threading.Lock() mutexB = threading.Lock() if __name__ == '__main__': t1 = MyThread1() t2 = MyThread2() t1.start() t2.start()
避免死锁
''' 天猫精灵:小爱同学 小爱同学:在 天猫精灵:现在几点了? 小爱同学:你猜猜现在几点了 ''' import threading class XiaoAi(threading.Thread): def __init__(self, cond): super().__init__(name='小爱同学') # self.lock = lock self.cond = cond def run(self): with self.cond: self.cond.wait() print('{}:在'.format(self.name)) self.cond.notify() self.cond.wait() print('{}:你猜呀'.format(self.name)) self.cond.notify() # self.lock.acquire() # print("{}:在".format(self.name)) # self.lock.release() # # self.lock.acquire() # print("{}:你猜猜".format(self.name)) # self.lock.release() class TianMao(threading.Thread): def __init__(self, cond): super().__init__(name='天猫精灵') self.cond = cond def run(self): with self.cond: self.cond.acquire() print('{}:小爱同学'.format(self.name)) self.cond.notify() self.cond.wait() print('{}:现在几点了'.format(self.name)) self.cond.notify() self.cond.wait() if __name__ == '__main__': # mutex = threading.RLock() cond = threading.Condition() xiaoai = XiaoAi(cond) tianmao = TianMao(cond) # 启动顺序很重要 xiaoai.start() tianmao.start()
''' 多任务版udp聊天: 1 创建套接字 2 绑定本地信息 3 获取对方IP和端口 4 发送、接收数据 5 创建两个线程,去执行功能 ''' import socket import threading def recv_msg(udp_socket): '''发送数据''' while True: recv_data = udp_socket.recvfrom(1024) print(recv_data) def send_msg(udp_socket, dest_ip, dest_port): '''接收数据''' while True: send_data = input('发送的数据:') udp_socket.sendto(send_data.encode('gbk'), (dest_ip, dest_port)) def main(): '''完成UDP聊天器''' # 1 创建套接字 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 2 绑定本地信息 udp_socket.bind(('', 7890)) # 3 获取对方IP和端口 dest_ip = '192.168.1.6' # 对方的ip dest_port = 8080 # 对方的端口 t_recv = threading.Thread(target=recv_msg, args=(udp_socket,)) t_send = threading.Thread(target=send_msg, args=(udp_socket,dest_ip, dest_port)) t_recv.start() t_send.start() if __name__ == '__main__': main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。