线程


python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用

代码:

import threading
import time
def hello():
   for index in range(5):
       print("我是 hello-------------------",end="\n")
       time.sleep(1)
def word():
   for index in range(5):
       print("我是 word" + str(index))
       time.sleep(2)
if __name__ == "__main__":
   # 创建线程对象
   t1 = threading.Thread(target=hello)
   # 创建线程对象
   t2 = threading.Thread(target=word)
   # 执行线程
   t1.start()
   # 执行线程
   t2.start()


注意

可以明显看出使用了多线程并发的操作,花费时间要短很多

当调用start()时,才会真正的创建线程,并且开始执行

target=方法名称,这个方法名称不能加括号,如果加上括号就变成了执行方法了而不是创建线程对象


enumerate查看线程


for threa_name in threading.enumerate():
   print(threa_name)


Python学习笔记(23)- 多线程_java

一般主线程会等待所有的子线程结束后才结束,并且每个线程默认有一个名字,python会自动为线程指定一个名字。当线程的run()方法结束时该线程完成。无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。


继承Thread类实现多线程


python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程。


# 继承Thread类实现多线程
import threading

class MyThread(threading.Thread):
   # 继承thread类之后一般都需要重写一下run方法
   def run(self):
       print("开始执行run方法")

if __name__ == "__main__":
   # 创建线程对象
   t = MyThread()
   # 执行线程时,会自动调用run方法
   t.start()

Python学习笔记(23)- 多线程_java_02


全局变量共享


实例

import threading
import time


num = 100
def set_num():
   global num
   for i in range(5):
       num += 1
   print("set_num-----------" + str(num))

def get_num():
   print("get_num-----------" + str(num))

if __name__ == "__main__":
   t1 = threading.Thread(target=set_num)
   t2 = threading.Thread(target=get_num)
   t1.start()
   t2.start()

   time.sleep(5)
   print("__main__-----------" + str(num))

Python学习笔记(23)- 多线程_java_03


Args参数共享


注意:使用args参数传值的话,必须使用可变类型的数据(列表、字典、可变集合),否则将不能共享

import threading
import time

def set_num(temp_num):
   temp_num.append(5)
   print("set_num-----------" + str(temp_num))

def get_num(temp_num):
   # 停顿1秒来保证数据共享效果
   time.sleep(1)
   print("get_num-----------" + str(temp_num))

if __name__ == "__main__":
   # 使用args参数传值的话,必须使用可变类型的数据(列表、字典、可变集合),否则将不能共享
   nums = [1234]
   t1 = threading.Thread(target=set_num, args=(nums,))
   t2 = threading.Thread(target=get_num, args=(nums,))
   t1.start()
   t2.start()
   time.sleep(5)
   print("__main__-----------" + str(nums))


共享全局变量会出现抢资源问题,好比1个线程同时执行到为一个变量赋值时还没有保存成功,第二个线程开始执行将值改变之后,在到第1个线程执行保存值时就将刚刚第二个线程的值直接覆盖问题。


实例

import threading
import time


num = 0
def set_num1():
   global num
   for i in range(100000):
       num += 1

   print("set_num-----------" + str(num))

def set_num2():
   global num
   for i in range(100000):
       num += 1
       # 互斥所关闭
   print("get_num-----------" + str(num))

if __name__ == "__main__":
   t1 = threading.Thread(target=set_num1)
   t2 = threading.Thread(target=set_num2)
   t1.start()
   t2.start()

   time.sleep(5)
   print("__main__-----------" + str(num))


Python学习笔记(23)- 多线程_java_04

应该结果是200000才对,现在最后的答案完全不对,所以就会出现多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确,那么这个时候就需要使用同步来解决此问题,互斥锁就是让某一个线程操作变量的时候要么操作完毕,要么不操作


互斥锁

threading模块中定义了Lock类,可以方便的处理锁定:

#
 创建锁

mutex = threading.Lock()

#
 锁定

mutex.acquire()

#
 释放

mutex.release()


注意:

如果这个锁之前是没有上锁的,那么acquire不会堵塞

如果在调用acquire对这个锁上锁之前 它已经被 其他线程上了锁,那么此时acquire会堵塞,直到这个锁被解锁为止

Python学习笔记(23)- 多线程_java_05

这个时候就可以解决刚刚的问题了,最终结果永远是正确的

Python学习笔记(23)- 多线程_java_06


封装dup多线程聊天机器人


import socket
import threading

class ClientSocket(threading.Thread):

   def __init__(self):
       # 没有该语句的话则会出现Python RuntimeError: thread.__init__() not called异常
       threading.Thread.__init__(self)
       self.udp_clien = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
       self.udp_clien.bind((""8888))

   def send_msg(self):
       while True:
           msg = input("请输入数据")
           self.udp_clien.sendto(msg.encode("utf-8"), ("192.168.153.1"8080))
   def rev_msg(self):
       while True:
           msg = self.udp_clien.recvfrom(1024)
           print(f"{msg[0].decode('utf-8')},{msg[1]}")

   def run(self):
       t1 = threading.Thread(target=self.send_msg)
       t2 = threading.Thread(target=self.rev_msg)
       t1.start()
       t2.start()
if __name__ == "__main__":
   c = ClientSocket()
   c.start()


Python学习笔记(23)- 多线程_java_07

Python学习笔记(23)- 多线程_java_08






Python学习笔记(23)- 多线程_java_09