Python日常笔记(23)- 多线程

线程

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会自动为线程指定一个名字。当线程的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()

全局变量共享

实例

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))

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 = [1, 2, 3, 4]
   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))


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

互斥锁

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

# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()

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

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

封装dup多线程聊天机器人

扫描二维码关注公众号,回复: 10810875 查看本文章
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日常笔记』,专注于 Python爬虫等技术栈和有益的程序人生,会将一些平时的日常笔记都慢慢整理起来,也期待你的关注和阿超一起学习,公众号回复【csdn】优质资源。

发布了55 篇原创文章 · 获赞 16 · 访问量 9510

猜你喜欢

转载自blog.csdn.net/duchaochen/article/details/105069036