Python 第三十五章 线程 构建线程+线程开启速度+线程pid+数据共享+join+互斥锁+守护线程+其他方法

线程基本理论

"""
1.线程是:
一条流水线的工作流程
进程:在内存中开启一个进程空间,将主进程的所有的资源数据复制一份,然后调用cpu去执行
具体描述:
在内存中开启一个进程空间,将主进程的所有的资源数据复制一份,然后调用线程去执行代码
***进程是资源单位,用于划分空间
***线程是执行单位,用于执行,线程是CPU中最小的执行单位

开启一个进程的过程:
进程会在内存中开辟一个进程空间,将主进程的资数据全部复制一份,线程会执行里面的代码

2.线程vs进程
    1.开启进程的开销大,比开启线程的开销大很多
    2.开启线程的速度非常快,快到几十倍到上百倍
    3.线程与线程之间可以共享数据,进程与进程之间需要借助队列等方法实现通信
    进程内部的数据是共享的,进程里面的所有线程
    进程与进程之间是有隔离的,利用queue队列可以通信
    
总结:
线程:开销小,执行速度快,同一个进程下的线程资源内存级别可共享
进程:开销大,执行速度慢,不同进程下的数据内存级别不共享,只能通过队列通信

3.线程的应用:
    并发:一个cpu看起来像是同时执行多个进程
    单个进程下开启是哪个线程:
    开启三个进程并发的执行任务
    一般使用多线程进行开发
    
    使用进程还是使用线程:
    一个软件:例如文件编辑器
    1.输入文字
    2.在屏幕中显示
    3.保存在磁盘中
    这个时候开启多线程就会非常好用了,优点:
    数据可以共享,开销小,速度快
    
4.主线程和子线程的关系:  
主线程和子线程没有地位之分,但是一个进程,最少需要一个主线程执行任务,当执行完成,
主线程需要等待其他子进程执行完成,才能结束本线程
"""

线程相关方法

开启线程的两种方式

# 第一种方式 函数方法
from threading import Thread
import time
def task(name):
    print(f'{name} is running')
    time.sleep(1)
    print(f'{name} is gone')

# 线程可以不再main下面写,便于理解还是写上吧

if __name__ =='__main__':
    t1 = Thread(target=task,args=('zs',)) # 涉及到代码都是主线程执行
    t1.start()
    print('==主线程') # 线程是没有主次之分

# 第二种方式 类方法
from threading import Thread
import time
class MyThread(Thread):
    def __init__(self,name,l1,ls1):
        super().__init__()
        self.name = name
        self.l1 = l1
        self.ls1 = ls1
    def run(self):
        print(f'{self.name,self.l1,self.ls1} is running')
        time.sleep(1)
        print(f'{self.name,self.l1,self.ls1} is gone')
if __name__ =='__main__':
    t1 = MyThread('zs',[1,2,3],'11')
    t1.start()
    print('==主进程')
from threading import Thread
from multiprocessing import Process
import time
def task(name):
    print(f'{name} is running')
    time.sleep(1)
    print(f'{name} is gone')

# 线程可以不再main下面写,便于理解还是写上吧

if __name__ =='__main__':
    # 在主进程下开启主线程
    t1 = Process(target=task,args=('zs',)) # 涉及到代码都是主线程执行
    t1.start()
    print('==主线程') # 线程是没有主次之分

多线程多进程开启的速度区别

"""
多线程多进程开启的速度区别
开启速度上,线程开启比进程快很多
"""
# 多线程启动速度慢一些
from multiprocessing import Process
import os
import time

def task():
    print(f'子进程{os.getpid()} is running')
    print(f'子进程{os.getpid()} is gone')

if __name__ == '__main__':
    start_time = time.time()
    t = Process(target=task)
    t.start()
    t1 = Process(target=task)
    t1.start()
    t2 = Process(target=task)
    t2.start()
    t3 = Process(target=task)
    t3.start()
    print(f'主进程{os.getppid()}结束') # 进程有主次之分,运行速度比线程慢
    print(f'{time.time()-start_time}')
# 输出
# 子进程19516 is running
# 子进程19516 is gone
# 主进程590结束
# 0.009748220443725586
# 子进程19517 is running
# 子进程19517 is gone
# 子进程19518 is running
# 子进程19518 is gone
# 子进程19519 is running
# 子进程19519 is gone

# 多线程执行速度快
from threading import Thread
from threading import activeCount
import time
import os
def task():
    print(f'子线程{os.getpid()} is running')
    print(f'子线程{os.getpid()} is gone')

if __name__ == '__main__':
    start_time = time.time()
    t = Thread(target=task)
    t.start()
    t1 = Thread(target=task)
    t1.start()
    t2 = Thread(target=task)
    t2.start()
    t3 = Thread(target=task)
    t3.start()
    print(f'主线程{os.getpid()}结束') # 线程没有主次之分 几乎同时执行完
    print(f'{time.time()-start_time}')
# 输出
# 子线程19533 is running
# 子线程19533 is gone
# 子线程19533 is running
# 子线程19533 is gone
# 子线程19533 is running
# 子线程19533 is gone
# 子线程19533 is running
# 子线程19533 is gone
# 主线程19533结束
# 0.0005669593811035156

线程进程pid

from threading import Thread
import os
def task():
    print(f'{os.getpid()}')
    print(f'{os.getpid()}')

if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    t.join()
    print(f'{os.getpid()}') # 同一个进程下,线程的pid都是一样的
# 输出
# 19135
# 19135
# 19135

同一进程内线程是共享数据

from threading import Thread
x = 3
def task():
    """
    修改全局变量的值
    :return:
    """
    global x
    x = 100

if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    t.join()
    print(f'{x}') # 同一个进程内,线程之间的数据是共享的
# 输出100

线程的其他方法

from threading import Thread
from multiprocessing import Process
from threading import currentThread
from threading import enumerate
from threading import activeCount
import time
import os
x = 3
def task():
    global x
    x = 100
    time.sleep(1)
    print(os.getpid())

# 对象的属性
if __name__ =='__main__':
    t1 = Thread(target=task) # t1 线程
    # name 设置线程名
    t1.start()
    time.sleep(2)
    print(t1.isAlive()) # 判断线程是否活着
    # False

    print(t1.getName()) # 获取线程名
    # Thread-1

    t1.setName('zs') # 设置线程名**
    print(t1.name)
    # zs

    print(f'==主线程{x}') # 同一进程内的资源数据对于这个进程的多线程来说是共享的

# 模块的属性
if __name__ =='__main__':
    t1 = Thread(target=task,name=('zs')) # 涉及到代码都是主线程执行
    t2 = Thread(target=task,name=('zs2')) # 涉及到代码都是主线程执行
    t1.start()
    t2.start()
    print(currentThread()) # 获取当前线程的对象
    # <_MainThread(MainThread, started 140736975586240)>

    print(enumerate()) # 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
    # [<_MainThread(MainThread, started 140736975586240)>, <Thread(zs, started 123145558224896)>, <Thread(zs2, started 123145563480064)>]

    print(activeCount()) # ***返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
    # 3

    print('==主线程')

join

# join 阻塞 告诉主线程要等待子线程执行完毕再执行主线程
# join 将执行的子线程和主线程变成串行,子线程和子线程之间是并行
# .start().join().start().join().start().join()是串行
# .srart().start().start().join().join().join()是并发
# for i in t  t.start()  for i in t1 t1.join() 是并发
from threading import Thread
import time
def task(name):
    print(f'{name} is running')
    time.sleep(1)
    print(f'{name} is gone')

if __name__ == '__main__':
    start_time = time.time()
    t1 = Thread(target=task,args=('海狗1',))
    t2 = Thread(target=task,args=('海狗2',))
    t3 = Thread(target=task,args=('海狗3',))
    # 串行
    t1.start()
    t1.join()

    t2.start()
    t2.join()

    t3.start()
    t3.join()
    print(f'===主线程{time.time()-start_time}') # 线程没有主次之分

# 输出
# 海狗1 is running
# 海狗1 is gone
# 海狗2 is running
# 海狗2 is gone
# 海狗3 is running
# 海狗3 is gone
# ===主线程3.0098721981048584

from threading import Thread
import time
def task(name):
    print(f'{name} is running')
    time.sleep(1)
    print(f'{name} is gone')

if __name__ == '__main__':
    start_time = time.time()
    t1 = Thread(target=task,args=('海狗1',))
    t2 = Thread(target=task,args=('海狗2',))
    t3 = Thread(target=task,args=('海狗3',))

    # 并发
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    print(f'===主线程{time.time()-start_time}') # 线程没有主次之分
# 输出
# 海狗1 is running
# 海狗2 is running
# 海狗3 is running
# 海狗1 is gone
# 海狗2 is gone
# 海狗3 is gone
#
# ===主线程1.0116689205169678

守护线程

# 守护线程:守护非子线程和主线程
# 什么时候结束:
# 如果守护线程的生命周期小于其他线程,会先结束
# 否则等待其他非守护子进程以及主线程结束之后结束

from threading import Thread
import time

def sayhi(name):
    print('你滚!')
    time.sleep(2)
    print('%s say hello' %name) # 先执行子线程

if __name__ == '__main__':
    t = Thread(target=sayhi,args=('egon',))
    # t.setDaemon(True) #必须在t.start()之前设置
    t.daemon = True
    t.start()  # 线程的开启速度要比进程快很多

    print('主线程') # 最后执行主线程
# 输出
# 你滚!
# 主线程


# 守护子线程睡的短,非子线程睡的久,其他非子线程还没有结束,守护子线程也未结束,继续执行,end123输出,都结束完了,主线程结束
from threading import Thread
import time

def foo():
    """
    先执行子线程
    :return:
    """
    print(123)  # 1 先打印123
    time.sleep(1) # 子线程睡了,只睡1秒,下面的不执行,开始走t2
    print("end123")  # 4 接着主进程的输出,再打印end123,继续往下走,走t2

def bar():
    """
    再执行子线程
    :return:
    """
    print(456)  # 2 再打印456
    time.sleep(3) # 子进程睡了,睡了3秒,下面不执行
    print("end456")  # 5 接着t1的输出,再打印end456


t1=Thread(target=foo)
t2=Thread(target=bar)

t1.daemon=True # 只设置t1守护主线程
t1.start() # 启动t1
t2.start()
print("main-------")  # 3 # 最后执行主线程 最后走主进程 主进程监测到子进程还没有结束,继续走,此时t1的守护时间已过,继续执行t1
# 输出
# 123
# 456
# main-------
# end123
# end456

# 守护子线程睡的久 其他非子线程和主线程都执行完了,守护子线程也结束,不再执行守护子线程的代码,end123不输出
from threading import Thread
import time

def foo():
    print(123)  # 1
    time.sleep(3)
    print("end123")

def bar():
    print(456)  # 2
    time.sleep(1)
    print("end456")  # 4


t1=Thread(target=foo)
t2=Thread(target=bar)

t1.daemon=True
t1.start()
t2.start()
print("main-------")  # 5
# 输出
# 123
# 456
# main-------
# end456



# 守护子线程和非子线程睡的时间一样,非子线程和主线程都结束了,守护线程也结束了,不再执行守护子线程的代码,end123不输出
from threading import Thread
import time

def foo():
    print(123)
    time.sleep(3)
    print("end123")

def bar():
    print(456)
    time.sleep(1)
    print("end456")


t1=Thread(target=foo)
t2=Thread(target=bar)

t1.daemon=True
t1.start()
t2.start()
print("main-------")
# 输出
# 123
# 456
# main-------
# end456

互斥锁

from threading import Thread
import time
import random

x = 100 # x被修改 x = 99
def task():# ①
    global x # 再执行修改全局变量 x = 99
    temp = x # ③ 先执行temp = 100,100个100
    time.sleep(random.randint(1,3)) # 开始随机睡,有一个temp醒得快,开始往下走,其他的temp还在睡
    # 其他的temp开始醒来,继续往下执行 都执行temp = 100-1 = 99(执行速度快会是99,慢的话,99~0都有可能)
    temp = temp -1 # temp = 100-1 = 99
    x = temp # x = 99
    print(f'这些是子线程{x}')

# 先走函数def task ,函数里面的代码不执行
if __name__ == '__main__': # 走if开始执行接口
    l1 = [] # 定义一个列表
    for i in range(100): # ② 循环i 100次
        t = Thread(target = task) # Thread(target = task)实例化一个子线程t,Thread是线程类 target = task 将task传入实例化对象中
        l1.append(t) # 将实例化对象加入l1列表中,得到100个实例化对象
        t.start() # start()调用函数,开始启动task里面的代码
    print('开始启动子线程')

    for i in l1: # ④ 循环100个实例化对象
        i.join() # 每次都执行的子线程都会阻塞不执行主线程,使用for i in 其他的子线程是并发执行
    print('阻塞子线程')
    print(f'主线程{x}') # ⑤主线程99



from threading import Thread
import time
import random

x = 100
def task():
    time.sleep(random.randint(1,2))
    global x
    temp = x
    time.sleep(random.randint(1,3))
    temp = temp -1
    x = temp


if __name__ == '__main__':
    l1 = []
    for i in range(100):
        t = Thread(target = task)
        l1.append(t)
        t.start()

    for i in l1:
        i.join()
    print(f'主线程{x}') # 主线程98


from threading import Thread
import time
import random

x = 100
def task():
    global x
    temp = x
    temp = temp -1
    x = temp


if __name__ == '__main__':
    l1 = []
    for i in range(100):
        t = Thread(target = task)
        l1.append(t)
        t.start()

    for i in l1:
        i.join()
    print(f'主线程{x}') # 主线程0
# 多个任务共抢一个资源数据,保证数据的安全目的,要让其串行,串行可以用互斥锁

from threading import Thread
from threading import Lock
import time
import random

x = 100
def task(lock):
    lock.acquire()
    global x
    temp = x
    time.sleep(0.01)
    temp = temp -1
    x = temp
    lock.release()


if __name__ == '__main__':
    mutex = Lock()
    l1 = []
    for i in range(100):
        t = Thread(target = task,args=(mutex,))
        l1.append(t)
        t.start()

    time.sleep(3)
    print(f'主线程{x}') #主线程0
原文地址:https://www.cnblogs.com/zhangshan33/p/11402376.html