python线程

2、线程

2.1 定义

默认情况下,程序启动只有一个线程,这个线程就是主线程,线程是CPU调度的基本单位

2.2 统计线程的个数

import threading

print('hello')
print('#####统计当前线程运行的个数#######')
print(threading.active_count())


展示:
hello
#####统计当前线程运行的个数#######
1


注意点:
在没有添加进程的情况下,我们依旧可以找到一个线程,这个线程是主线程

2.3 创建多线程

    def __init__(self, group=None, target=None, name=None,
                 args=(), kwargs=None, *, daemon=None)

案例:

import threading
# print('hello')
# print('#####统计当前线程运行的个数#######')
# print(threading.active_count())

def calm():
    for i in range(10):
        print('第',i,'次冷静以下')

def smoke():
    for j in range(10):
        print('第',j,'只烟')


if __name__ == '__main__':
    # calm()
    # smoke()
    print('当前进程的线程个数',threading.active_count())
    # 创建多线程
    thread_smoke = threading.Thread(target=smoke)
    thread_calm = threading.Thread(target=calm)
    print('当前进程的线程个数',threading.active_count())
    # 守护主线程
    # thread_smoke.setDaemon(True)
    # thread_calm.setDaemon(True)

    # 调用
    thread_smoke.start()
    thread_calm.start()
    print('当前进程的线程个数',threading.active_count())
    # 守护子线程
    thread_calm.join()
    thread_smoke.join()
    print('当前进程的线程个数',threading.active_count())
    print('主线程已经结束')
    exit()
    
 
展示:
当前进程的线程个数 1
当前进程的线程个数 10 只烟
第 1 只烟
第 2 第只烟
第 当前进程的线程个数3   只烟
第 04 3 
次冷静以下只烟
第 
5 只烟第
第  1 次冷静以下
6 只烟第
 第 7 只烟
28 只烟
第 次冷静以下9 只烟

第 3 次冷静以下
第 4 次冷静以下
第 5 次冷静以下
第 6 次冷静以下
第 7 次冷静以下
第 8 次冷静以下
第 9 次冷静以下
当前进程的线程个数 1
主线程已经结束

2.4 多线程的注意点

1、线程的执行是无序的,因为是CPU进行调度的

2、守护主线程,主线程退出,那子线程直接销毁

import threading
import time
# print('hello')
# print('#######统计当前线程运行的个数######')
# print(threading.active_count())


def calm():
    for i in range(10):
        time.sleep(0.1)
        print('第',i,'次冷静一下')

def smoke():
    for j in range(10):
        time.sleep(0.1)
        print('第',j,'支烟')



if __name__ == '__main__':
    # smoke()
    # calm()
    print('当前进程的线程个数',threading.active_count())
    #创建多线程
    thread_smoke = threading.Thread(target=smoke)
    print('当前进程的线程个数', threading.active_count())

    thread_calm = threading.Thread(target=calm)
    #守护主线程
    thread_smoke.setDaemon(True)
    thread_calm.setDaemon(True)


    #调用
    thread_smoke.start()
    thread_calm.start()
    # time.sleep(0.1)

    # thread_calm.join()
    # thread_smoke.join()
    print('当前进程的线程个数', threading.active_count())
    print('主线程已经结束')
    exit()
    
    展示:
    当前进程的线程个数 1
    当前进程的线程个数 1
    当前进程的线程个数 3
    主线程已经结束

3、守护子线程,只有当子线程全部结束之后,主线程才结束

def calm():
    for i in range(10):
        time.sleep(0.1)
        print('第',i,'次冷静一下')

def smoke():
    for j in range(10):
        time.sleep(0.1)
        print('第',j,'支烟')



if __name__ == '__main__':
    # smoke()
    # calm()
    print('当前进程的线程个数',threading.active_count())
    #创建多线程
    thread_smoke = threading.Thread(target=smoke)
    print('当前进程的线程个数', threading.active_count())
    thread_calm = threading.Thread(target=calm)

    #调用
    thread_smoke.start()
    thread_calm.start()
    # time.sleep(0.1)
    
    thread_calm.join()
    thread_smoke.join()
    print('当前进程的线程个数', threading.active_count())
    print('主线程已经结束')
    exit()
    
    展示:
    当前进程的线程个数 1
当前进程的线程个数 10 支烟
第 0 次冷静一下
第 1 支烟
第 1 次冷静一下
第 2 支烟
第 2 次冷静一下
第 3 支烟
第 3 次冷静一下
第 4 次冷静一下
第 4 支烟
第 5 次冷静一下
第 5 支烟
第 6 支烟
第 6 次冷静一下
第 7 支烟
第 7 次冷静一下
第 8 次冷静一下
第 8 支烟
第 9 支烟
第 9 次冷静一下
当前进程的线程个数 1
主线程已经结束

4、子线程之间共享全局变量,就会造成资源的争抢问题

2.5 互斥锁的问题

问题:

因为线程之间共享全局变量,所以,在多线程几乎在同时运行的时候,几乎同时修改同一个全局变量的时候,就要进行控制

此时,需要互斥锁

当某个线程需要修改资源的时候,先将资源进行锁定,其他线程不能修改该线程

当线程修改完成之后,并且释放完互斥锁之后,其他的线程才可以使用

互斥锁保证在当前只有一个线程可以使用修改同一个资源

import threading

num = 0

def add_num1():
    global num
    for i in range(10000000):
        # 上锁
        lock_flag = lock_obj.acquire(True)
        if lock_flag:
            num += 1
            # 释放锁
            lock_obj.release()
    print('子线程1已经完成,此时得到的num',num)

def add_num2():
    global num
    for i in range(10000000):
        # 上锁
        lock_flag = lock_obj.acquire(True)
        if lock_flag:
            num += 1
            lock_obj.release()
    print('子线程2已经完成,此时得到的num',num)

# 程序入口
if __name__ == '__main__':

    lock_obj = threading.Lock()
    thread1 = threading.Thread(target=add_num1)
    thread2 = threading.Thread(target=add_num2)

    thread1.start()
    thread2.start()
    

展示:
子线程2已经完成,此时得到的num 19524417
子线程1已经完成,此时得到的num 20000000


注意点:
1、确保了关键代码只能由一个线程从头到尾完整的执行完成
2、阻止了多线程的并发操作,包含锁的代码其实还是单线程执行的,效率下降了;
   如果当前的程序出现了多个锁,可能会出现死锁的问题

2.6 死锁的问题

避免死锁的方法:

1、超时释放(timeout)

2、设计的时候,避免死锁

2.7 线程安全

2.7.1 队列
from threading import Thread
from queue import Queue
from queue import LifoQueue

# python2的写法
# from Queue import Queue

# 队列
def writedata():
    for i in range(20):
        # 判断队列是否已经满了,没有满就向队列中填充
        if not queue.full():
            queue.put(i)
        else:
            break

def readdata():
    for i in range(3):
        # 判断队列是否为空,不为空就从队列中取出数据
        if queue.qsize() != 0:
            data = queue.get()
            print(data)
        else:
            break
# def readdata1():
#     for i in range(2):
#         if queue.qsize() != 0:
#             data = queue.get()
#             print(data)
#         else:
#             break

if __name__ == '__main__':

    # 创建一个队列对象
    queue = Queue(5)
    thread1 = Thread(target=writedata)
    thread2 = Thread(target=readdata)
    # thread3 = Thread(target=readdata1)

    thread1.start()
    thread2.start()
    # thread3.start()
    

展示:
0
1
2
2.7.2 队栈
# 队栈
from threading import Thread
from queue import LifoQueue
import threading

def writedata1():
    for i in range(200000):
        # 上锁
        lock_flag = lock_obj.acquire(True)
        # 判断队栈是否已经满了,没有满就向队栈中填充数据
        if not q.full():
            q.put(i)
            lock_obj.release()
        else:
            lock_obj.release()
            break

def readdata1():
    for i in range(3):
        # 上锁
        lock_flag = lock_obj.acquire(True)
        # 判断队栈是否为空,不为空就从队栈中取出数据
        if q.qsize() != 0:
            data = q.get()
            print(data)
            lock_obj.release()
        else:
            lock_obj.release()
            break
def readdata2():
    for i in range(2):
        # 上锁
        lock_flag = lock_obj.acquire(True)
        if q.qsize() != 0:
            data = q.get()
            print(data)
            lock_obj.release()
        else:
            lock_obj.release()
            break


if __name__ == '__main__':
    lock_obj = threading.Lock()
    # 创建一个队栈对象
    q = LifoQueue(5000)
    thread1 = Thread(target=writedata1)
    thread2 = Thread(target=readdata1)
    thread3 = Thread(target=readdata2)

    thread1.start()
    thread2.start()
    thread3.start()
    
    
展示:
4461
4460
4459
5002
5001

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值