# 线程基础
"""
多任务的概念:就是操作系统可以同时运行多个任务
并发:指的是任务数多余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()