python学习3----多线程



102
多任务   同一时间多个任务执行  多个进程  
操作系统可以同事运行多个任务 多核的cpu已经非常的普及
单核的cpu也可以执行多个任务

#!/usr/bin/python
# Write Python 3 code in this online editor and run it.
print("Hello, Wo   rld!");
#线程的基本使用
#使用threading模块创建线程
'''子线程创建步骤
1 导入模块 threading
2 使用threading.thread()创建对象 (子线程对象)
3 指定子线程执行的分支
4 启动子线程  线程对象.start()

'''
import time
import threading
def saysorry():
	print("sorry")
	time.sleep(0.5)
if __name__  ==  "__main__":
	for i in range(5):
		#2 使用threading.thread()创建对象 (子线程对象)
		# threading.Thread(target = 函数名)

		th_obj = threading.Thread(target=saysorry)\
		
		#saysorry() #调用函数  单线程方式
		th_obj.start()
		#主线程等子线程结束才结束
	print("111111111111111111")#子线程与主线程同时执行
-----------------------------------------------------------------------------------------------
import time
import threading
def sing():
    for i in range(5):
        print  ("sing")
def dance():
    for i in range(5):
        print  ("dance")

if __name__  ==  "__main__":
    for i in range(5):
		#2 使用threading.thread()创建对象 (子线程对象)
		# threading.Thread(target = 函数名)
        th_obj_sing = threading.Thread(target=sing)
        th_obj_dance = threading.Thread(target=dance)
        th_obj_sing.start()
        th_obj_dance.start()

		#主线程等子线程结束才结束
    print("111111111111111111")#子线程与主线程同时执行

主线程的作用是创建子线程
等子线程结束才关闭
子线程 程序的一个分支

导入模块  import threading
创建对象 threading.Thread(target=funcname)
启动子线程对象 线程对象.start()

----------------------------------------------------------------------------------
线程的数量
如何查看线程的数量
threading.enumerate()获取当前所有活跃的线程数量

args=(参数1,参数2,。。。。)
元祖与字典混合时  元祖后面加上一个逗号

线程是被系统独立调度和分派的最小系统

无法控制线程调度程序  但可以通过别的方式来影响线程调度的方式
说明:多线程程序的执行顺序是不确定的,当执行到sleep语句的时候,线程被阻塞blocked
,到sleep结束后,线程进入就绪runnable状态,等待调度 而线程调度将自行选择一个线程执行。


线程参数  
元祖 
threading.tread(targer=xxxx,agrs=(param1,param2...))
字典 
threading.tread(targer=xxxx,kwargs=(参数1:param1,参数2:param2...))
混合
threading.tread(targer=xxxx,agrs=(param1,param2,...),kwargs=(参数1:param1,参数2:param
线程的顺序  
线程执行无法 由cpu自己算法调度 程序员无法控制




------------------------------------------------------------------------------------------
线程的守护  守护线程
能够使用setDaemon 设置子线程守护主线程

子线程在主线程的时候自动退出

import time
import threading

def work1():
    for i in range(10):
        print("正在执行work1.。。。。")
        time.sleep(0.5)

if __name__=="__main__":
    #创建线程对象
    thread_work= threading.Thread(target=work1)
    #线程守护 子线程守护主线程
    #setDaemon(True)  表示子线程守护了主线程 主线程结束后 子线程也结束
    thread_work.setDaemon(True)
    thread_work.start()

    #睡眠2秒
    time.sleep(2)
    print("over !!!!!!")
    #让程序退出 主线程主动结束
    exit() #如果没有此行命令    thread_work.setDaemon(True) 主线程结束  但子线程也没有结束 
---------------------------------------------------------------------------------------------

你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。
所以我认为它们最关键的点就是:是否是『同时』。



做并发编程之前,必须首先理解什么是并发,什么是并行,什么是并发编程,什么是并行编程。

并发(concurrency)和并行(parallellism)是:

解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
解释三:并行是在多台处理器上同时处理多个任务,如hadoop分布式集群。并发是在一台处理器上“同时”处理多个任务。

当一个计算机 多个任务的时候其实就是让操作系统轮流让各个任务交替执行
雨露均沾
2.8G 2.8亿次

并发 指的是任务数大于cpu核数
并行 任务数小于cpu核数 即任务一块执行

并发:任务数大于cpu核心数
并行:任务数小于或等于cpu的核心数
---------------------------------------------------------------------------------------
自定义线程类
通过集成threading.Thread 可以实现自定义线程

方法:
让自定义类继承 threading.thread类
重写父类(threading.Thread) run 方法
通过创建子类对象 让子类对象.start()就可以启动子线程

import time
import threading
'''
def run():
    pass 
def start():
'''

#自定义类名
class mythread11(threading.Thread):
    def __init__(self,num):
        #必须先去调用父类的init方法 此处采用的方法是 super()
        super().__init__()
        self.num = num

    #重写父类的run方法
    def run(self):
        for i in  range(8): #self.name 线程的名字
            #self.name 从父类继承的一个属性
            print("正在执行子线程run方法...",i,"  ",self.name,"  ",self.num)
            time.sleep(0.5)

if __name__=="__main__":
    myth = mythread11(10)
    myth.start()  #调用start 执行run  start函数里面执行run函数
    print("xxxxxxxxxxx")

'''
导入模块
创建类并且继承threading.Thread
calss mythread(threading.Thread)
重写父类的方法 
def run(self)
    ...
创建对象并且调用.start()

myth = mythread()
mythread.start()
底层原理
Thread类
run方法
start()
start中调用run方法
自定义线程类的init方法问题
子类先通过super调用父类的初始化方法 子类再初始化
def __init__(self,num):
    #先调用父类的init方法
    super().__init__()
    self.num  =num
'''
--------------------------------------------------------------------

##多线程共享全局变量
#多线程方法中可以共享全局变量
#函数1对函数的全局变量1的值修改 与此同时函数2中获取全局变量的值
import threading
import time
num =0
def work1():
    #申明变量是一个全局变量 否则不可以修改
    #num =0
    global  num
    for i in range(10000000):
        num +=1 #1、获取num的值 2、num值加1 3、赋值
    print("work1 num =",num)

def work2(): # 
    global  num
    for i in range(10000000):
        num +=1
    print("work2 num =",num)
if __name__ == "__main__":
    #创建子线程
    t1 = threading.Thread(target = work1)
    t2 = threading.Thread(target = work2)
    #启动线程
    t1.start()
    #如果让一个线程运行完再运行下一个线程 就可以解决资源竞争 但这样就不存在多线程的含义了
    #优先让t1线执行 执行完毕后 t2才可以执行
    t1.join()
    #t1.join()的缺点  把多线程变成了单线程 影响整体的性能
    t2.start()
    #多线程之间可以共享变量  存在资源竞争
    while len(threading.enumerate())!=1: #等子线程结束后再执行
        time.sleep(1)

    #在t1和t2线程完毕后 打印 num
    print("main-------------",num)  ##最后输出的结果小于真实值

    ##多线程 共享全局变量问题
    #导致资源竞争的问题
    
    #加入两个线程函数均对同一个变量进行修改
    ###一千万加上一千万小于两千万的结果  造成资竞争
    ------------------------------------------------------------------------------

#同步:多任务
#异步:指的是多个任务之间执行没有先后顺序  可以同时执行 执行的先后顺序不会有影响 存在的多条运行主线
#同步:多任务直接执行的顺序有先后的顺序
#解决线程同时修改全局变量的方式
#线程锁的机制
#A线程获得 g_num的使用权并且加上了机制锁 此时BC线程无法使用G_num,BC必须等到A线程不再使用g_num并且解锁后,才能使用g_num.
#蚂蚁森林种树的机制
#同步 再多任务中 执行有先后的顺序 一个执行完毕  另外一个才可以执行
#异步 在多任务的执行没有先后的顺序 多个任务同时执行
#线程的锁机制 当线程获取资源后 立刻进行锁定  资源使用完毕后再解锁 有效的保证同一时间只有一个线程在使用资源


#---------------------------------------------#
#互斥锁
#利用互斥锁解决资源竞争的问题
'''
三大步骤  
创建一把锁
lock1 = threading.Lock()
上锁
lock1.acquire()
解锁
lock1.release()
'''
'''
当多个线程几乎同时修改某一个共享数据的时候 需要进行同步控制
线程同步可以保证几个线程安全访问竞争资源 最简单的同步机制是引入互斥锁
互斥锁为资源引入一个状态 锁定/非锁定
某线程要更改共享数据时,先将其锁定
threading 模块中定义了lock锁 可以方便的处理锁定
创建锁
mutex = threading.lock()
锁定
mutex.acquire()
释放
mutex.release()
如果这个锁之前没有加上锁的 那么acquire不会堵塞的
如果在调用acquire对这个锁之前 他已经被其他线程上了锁 那么此时acquire会堵塞  直到这个锁被解锁为止
使用互斥锁对同一变量进行两百万加法的操作
'''

'''
过程:
创建一把互斥锁
在使用资源之前要锁定
使用完资源后  要解锁释放
'''

##多线程共享全局变量
#多线程方法中可以共享全局变量
#函数1对函数的全局变量1的值修改 与此同时函数2中获取全局变量的值
import threading
import time
num =0
def work1():
    #申明变量是一个全局变量 否则不可以修改
    #num =0
    global  num
    lock1.acquire()
    for i in range(2000000):
        ###锁定此行  尽可能把资源锁定的最小 锁定紧缺资源 
        ##上锁的时候兼顾性能和原则
        #上锁  
        #lock1.acquire() #可以把锁放在外面 可以解决程序慢的问题 避免频繁的上锁解锁
        num +=1 #1、获取num的值 2、num值加1 3、赋值
        #lock1.release()
    lock1.release()
    print("work1 num =",num)

def work2(): # 
    global  num
    lock1.acquire()
    for i in range(100000):
        #上锁 还必须为是同一把锁 才可以互斥
        #lock1.acquire()
        num +=1
    lock1.release()#解锁 他在用的时候别人不可以用
    print("work2 num =",num)
if __name__ == "__main__":
    # 创建一把互斥锁
    lock1= threading.Lock()
    #创建子线程
    t1 = threading.Thread(target = work1)
    t2 = threading.Thread(target = work2)
    #启动线程
    t1.start()
    #如果让一个线程运行完再运行下一个线程 就可以解决资源竞争 但这样就不存在多线程的含义了
    #优先让t1线执行 执行完毕后 t2才可以执行
    #t1.join()
    #t1.join()的缺点  把多线程变成了单线程 影响整体的性能
    t2.start()
    #多线程之间可以共享变量  存在资源竞争
    while len(threading.enumerate())!=1: #等子线程结束后再执行
        time.sleep(1)

    #在t1和t2线程完毕后 打印 num
    print("main-------------",num)  ##最后输出的结果小于真实值

    ##多线程 共享全局变量问题
    #导致资源竞争的问题
    
    #加入两个线程函数均对同一个变量进行修改
    ###一千万加上一千万小于两千万的结果  造成资竞争
--------------------------------------------------------------------------------------
死锁
#!/usr/bin/python
# Write Python 3 code in this online editor and run it.
print("Hello, World!")
#死锁 在线程间共享多个资源的时候 如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁
'''
死锁会造成应用停止
'''
import threading
#定义函数  根据下表获取列表元素值
def get_value(index):
    list_data=[11111,21111,311111,411111,5111111]
    #上锁
    lock1.acquire()
    #判断下表是否越界
    if index >= len(list_data):
        print( "下标越界,",index)
        return #越界后等待 5的资源释放
    print(list_data[index])
    #解锁  越界后 后面一直在等待形成死锁
    lock1.release()


if __name__ =="__main__":
    #创建一把锁
    lock1 = threading.Lock()
    #循环创建10个线程
    for i in range(10):
        t1 = threading.Thread(target=get_value, args=(i,))
        t1.start()

#创建10个线程 观察资源的等待状态
'''
互斥锁的步骤
创建一把锁
lock1.threading.Lock()
上锁
lock1.acquire()
解锁
lock1.release()
互斥锁的使用原则 尽可能的减少锁定竞争资源

死锁:在多线程中,两个线程占用一些资源,而且同一时间都在等待对方释放资源,这种状态就是死锁状态
避免:锁使用完毕后 要及时的释放
死锁要满足四个条件 锁的不是线程 而是共享的资源
'''
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值