Python每日笔记13

本次内容:线程

>> Python每日笔记—目录 <<

线程

多线程的使用

  1. Thread()
    group:线程组,目前只能使用None
    target:执行的目标任务名
    *args:以元组的方式给执行任务进行传参
    **kwargs:以字典的方式进行传参
    name:线程名称,一般不进行设置
# 导入线程模块
import threading
import time
def sing():
    # 获取当前线程current_thread()
    current_thread = threading.current_thread()
    print("sing:", current_thread)
    # 休眠sleep   打印10次后休眠当前线程
    for i in range(5):
        print("唱歌中。。。")
        time.sleep(0.5)

def dance():
    # 获取当前线程
    current_thread = threading.current_thread()
    print("dance:", current_thread)
    # 休眠sleep   打印10次后休眠当前线程
    for i in range(3):
        print("跳舞中。。。")
        time.sleep(0.7)

# 调用一下
#sing()  # sing: <_MainThread(MainThread, started 11152)>

if __name__ == '__main__':
    # 获取当前线程
    current_thread = threading.current_thread()
    print("main_thread",current_thread) # main_thread <_MainThread(MainThread, started 3304)>
    # 创建子线程,分别执行sing()和dance()内容
    sing_thread = threading.Thread(target=sing, name="sing_thread")
    dance_thread = threading.Thread(target=dance, name="dance_thread")

    # 启动线程
    # 运行结果交替输出,线程在争夺资源
    sing_thread.start()
    dance_thread.start()

线程参数

  1. 以元素的方式进行传参,元素里面元素的顺序和参数的参数顺序保持一致
  2. 以字典的形式进行传参,保证字典里面的key和函数参数名称一致
import threading
def show_info(name, age):
    print("name:%s age%d" % (name, age))

if __name__ == '__main__':
    '''
        1、以元素的方式进行传参,元素里面元素的顺序和参数的参数顺序保持一致
        2、以字典的形式进行传参,保证字典里面的key和函数参数名称一致
    '''
    sub_thread = threading.Thread(target=show_info, args=('张三', 30))
    sub_thread.start()

    sub_thread = threading.Thread(target=show_info, kwargs={
     'name': "李四", 'age': 20})
    sub_thread.start()

线程的另外一种创建方式 _thread

import _thread
import time
# 为线程定义一个函数
def print_time(thread_name, delay):
    count = 0
    while count < 5:
        time.sleep(delay)
        count += 1
        print("%s:%s"%(thread_name,time.ctime(time.time())))

# 创建两个线程
try:
    _thread.start_new_thread(print_time, ("Thread-1", 2))
    _thread.start_new_thread(print_time, ("Thread-2", 4))
except:
    print("Error:无法启动线程")
while 1:
    pass

start()启动线程

  1. 使用threading模块创建线程,我们可以通过threading。
  2. Thread继承创建一个线程的子类并且实例化之后调用start()方法启动方法
import threading
import time

exitFlag = 0    # 判断是否退出的变量
class my_thread(threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):  # 重写父类中的run方法
        print("开始线程:"+ self.name)
        print_time(self.name, self.counter, 5)
        print("退出线程:"+self.name)

# self.counter传给delay(休眠时间)     counter = 5
def print_time(thread_name, delay, counter):
    while counter:
        if exitFlag:
            thread_name.exit()
        time.sleep(delay)
        print("%s:%s"%(thread_name,time.ctime(time.time())))
        counter -= 1

# 创建新线程
thread1 = my_thread(1, 'Thread-1', 1)
thread2 = my_thread(2, 'Thread-2', 2)
thread1.start() # 执行的是run方法的内容!!
thread2.start()

守护线程

  1. 主线程会等待子线程结束之后再结束
    如果不想结束子线程怎么办?
  2. 解决方法:把子线程改成守护线程即可(setDaemon(true))
import threading
import time
def task():
    for i in range(5):
        print("任务执行中。。。%d" % i)
        time.sleep(0.5)

if __name__ == '__main__':
    '''创建一个子线程'''
    sub_thread = threading.Thread(target=task)
    sub_thread.setDaemon(True)  # 将该线程设置为守护线程
    sub_thread.start()  # 启动线程
    time.sleep(1)
    print("over")

线程共享全局变量

join(): 使某线程占用资源,直到此线程结束

import threading
import time
# 定义一个全局变量
g_list = []
# 添加数据的任务
def add_data():
    for i in range(3):
        g_list.append(i)
        print("add:",i)
        time.sleep(0.3)
    print("添加数据完成", g_list)
# 读取数据的任务
def read_data():
    print("read:", g_list)

if __name__ == '__main__':
    # 创建添加数据的子线程
    add_thread = threading.Thread(target=add_data)
    read_thread = threading.Thread(target=read_data)

    add_thread.start()
    # 让当前线程(主线程)等待添加数据的子线程完成以后,代码再继续执行
    add_thread.join()
    read_thread.start()

多线程全局变量案例

多线程操作全局变量的问题:

  1. 创建一个变量 num
  2. 第一个线程执行完之后,num的值递增到10000(每次递增1个单位)
  3. 第二个线程执行完之后,num的值递增到20000(每次递增1个单位)
import threading
import time
num = 0

def add1():
    global num
    for i in range(10000):
        num += 1
        # time.sleep(0.0001)    时间间隔
        print("num:", num)
    print("----num----", num)

if __name__ == '__main__':
    add1_thread = threading.Thread(target=add1)
    add2_thread = threading.Thread(target=add1)
    add1_thread.start()
    add1_thread.join()
    add2_thread.start()

线程锁

创建锁:lock = threading.Lock()
上锁:lock.acquire()
互斥锁:

  1. 可以保证一个时间段只有一个线程去执行代码,能够保证全局变量的数据没有问题
  2. 线程等待和互斥都是把多个任务改成单个任务去执行。
  3. 好处是能够保证数据的准确性,但执行的性能会下降

案例一:

案例中,task1中使用了锁,使得task1线程可以独占资源,task2需要等待task1结束后才开始执行。

import threading
g_num = 0
# 创建一个互斥锁
lock = threading.Lock() # Lock()本质上是一个函数,通过调用该函数可以创建一个互斥锁对象
# 创建一个函数,执行100万次任务
def task1():
    # 上锁
    lock.acquire()
    for i in range(10):
        global g_num
        g_num += 1
        print("task1=", g_num)
    # 数据计算完成
    # print("task1=", g_num)


def task2():
    for i in range(10):
        global g_num
        g_num -= 1
        print("task2=", g_num)
    # 数据计算完成
    # print("task2=", g_num)

if __name__ == '__main__':
    # 创建两个子线程
    oneThread = threading.Thread(target=task1)
    twoThread = threading.Thread(target=task2)
    # 使用互斥锁的方式,而不是用线程等待的方式,只执行一个线程
    oneThread.start()
    twoThread.start()
    # 输出结果:两个线程不再抢夺,task1循环执行完之后才会执行task2的循环

案例二:

import threading
# 创建互斥锁
lock = threading.Lock()
def get_value(index):
    # 上锁
    lock.acquire()
    my_list = [4, 6, 8]
    # 判断下标是否越界
    if index >= len(my_list):
        print("下标越界", index)
        # 不释放资源,后面无法执行
        lock.release()
        return
    # 根据下标去取值
    value = my_list[index]
    print(value)
    # 如果不释放,只打印一次value,并且把资源锁住
    # 释放后,会打印出所有的value
    lock.release()
if __name__ == '__main__':
    for i in range(10):
        # 每循环一次就创建一个子线程
        sub_thread = threading.Thread(target=get_value,args=(i,))
        sub_thread.start()

如果这篇文章对你有帮助的话,点个赞呗~

你可能感兴趣的:(多线程,python,thread,多进程)