ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python——多线程

2022-01-21 00:03:06  阅读:203  来源: 互联网

标签:20 Thread Python Jan threading 线程 time 多线程


1.多线程

        多线程类似于同时执行多个不同程序。

        多线程运行有如下优点:

  • 使用线程可以把占据长时间的程序中的任务放到后台去处理;
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度;
  • 程序的运行速度可能加快;
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

        每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

        每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

        指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。

  • 线程可以被抢占(中断)。
  • 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠)——即线程的退让。

线程的分类:

  • 内核线程:由操作系统内核创建和撤销。
  • 用户线程:不需要内核支持而在用户程序中实现的线程。

2.Python线程

        Python中使用线程有两种方式:函数或者用类来包装线程对象。

(1)函数式:

        调用 _thread 模块中的start_new_thread()函数来产生新线程。语法如下:

_thread.start_new_thread(function, args[, kwargs])

参数说明:

  • function:线程函数。
  • args:传递给线程函数的参数,他必须是个tuple类型。
  • kwargs:可选参数。

例:

import _thread
import time

# 为线程定义一个函数
def print_time(threadName, delay):
    count = 0
    while count < 5:
        time.sleep(delay)
        count += 1
        print("%s: %s" % (threadName, 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: Unable to start thread")

while 1:
    pass

运行结果:

Thread-1: Thu Jan 20 20:11:36 2022
Thread-2: Thu Jan 20 20:11:38 2022
Thread-1: Thu Jan 20 20:11:38 2022
Thread-1: Thu Jan 20 20:11:40 2022
Thread-2: Thu Jan 20 20:11:42 2022
Thread-1: Thu Jan 20 20:11:42 2022
Thread-1: Thu Jan 20 20:11:44 2022
Thread-2: Thu Jan 20 20:11:46 2022
Thread-2: Thu Jan 20 20:11:50 2022
Thread-2: Thu Jan 20 20:11:54 2022

线程的结束:

  • 一般依靠线程函数的自然结束;
  • 在线程函数中调用thread.exit(),抛出SystemExit exception,达到退出线程的目的。

3.线程模块

        Python3 通过两个标准库_thread和threading提供对线程的支持。

(1)_thread:

        提供了低级别的、原始的线程以及一个简单的锁,它相比于threading模块的功能还是比较有限的。

(2)threading模块:

        除了包含_thread模块中的所有方法外,还提供的其他方法:

  • threading.currentThread():返回当前的线程变量。
  • threading.enumerate():返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount():返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

(3)Thread类:

        除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

  • run():用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]):等待至线程中止。这阻塞调用线程直至线程的join()方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive():返回线程是否活动的。
  • getName():返回线程名。
  • setName():设置线程名。

(4)使用threading模块创建线程:

        通过直接从threading.Thread继承创建一个新的子类,并实例化后调用start()方法启动新线程,即它调用了线程的run()方法。

例:

import threading
import time

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, delay):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.delay = delay
    def run(self):
        print ("开始线程:" + self.name)
        print_time(self.name, self.delay, 5)
        print ("退出线程:" + self.name)

def print_time(threadName, delay, counter):
    while counter:
        if exitFlag:
            threadName.exit()
        time.sleep(delay)
        print ("%s: %s" % (threadName, time.ctime(time.time())))
        counter -= 1

# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("退出主线程")

运行结果:

开始线程:Thread-1
开始线程:Thread-2
Thread-1: Wed Jan  5 17:34:54 2022
Thread-2: Wed Jan  5 17:34:55 2022
Thread-1: Wed Jan  5 17:34:55 2022
Thread-1: Wed Jan  5 17:34:56 2022
Thread-2: Wed Jan  5 17:34:57 2022
Thread-1: Wed Jan  5 17:34:57 2022
Thread-1: Wed Jan  5 17:34:58 2022
退出线程:Thread-1
Thread-2: Wed Jan  5 17:34:59 2022
Thread-2: Wed Jan  5 17:35:01 2022
Thread-2: Wed Jan  5 17:35:03 2022
退出线程:Thread-2
退出主线程

 4.延时函数

(1)库:

        import time

(2)函数:

        time.sleep(seconds)

(3)参数:

        seconds延迟执行代码的秒数

例:

import time

while(1):
	print("Hello!geigei!")
	time.sleep(1)

5.锁

        Threading模块为我们提供了一个类,threading.Lock锁。当创建一个该类对象,在线程函数执行前,“抢占”该锁,执行完成后,“释放”该锁,确保每次只有一个线程占有该锁。这样对一个公共的对象进行操作时,则不会发生线程不安全的现象。

(1)线程锁(Lock):

        建立一个threading.Lock类对象lock,在run()方法中使用lock.acquire()获得该锁,则其他的线程就无法再获得该锁,就会阻塞在“if lock.acquire()”处,直到该锁被另一个线程释放:lock.release()。

        如果多个线程要调用多个现象,而A线程调用A锁占用了A对象,B线程调用B锁占用了B对象,A线程不能调用B对象,B线程不能调用A对象,则一直等待。这就造成了线程“死锁”。

(2)递归锁(RLock):

        又可称为可重入锁,该锁对象内部维护着一个Lock和一个counter对象。

        counter对象记录了acquire的次数,使得资源可以被多次require,最后当所有RLock被release后,其他线程才能获取资源。在同一个线程中,RLock.acquire可以被多次调用,利用该特性,可以解决部分死锁问题。

语法:

lock = threading.Lock()  # 创建线程锁

lock = threading.RLock()  # 创建递归锁(多个锁时用这个)

lock.acquire()  # 锁住

lock.release()  # 释放锁

例:

线程锁:

# 线程锁,加锁实例

import threading
import time

def chiHuoGuo(people, do):
    print("%s 吃火锅的小伙伴:%s" % (time.ctime(),people))
    time.sleep(1)
    for i in range(3):
        time.sleep(1)
        print("%s %s正在 %s 鱼丸"% (time.ctime(), people, do))
    print("%s 吃火锅的小伙伴:%s" % (time.ctime(),people))

# 继承父类threading.Thread
class myThread (threading.Thread):
    lock = threading.Lock()  # 线程锁
    def __init__(self, people, name, do):
        '''重写threading.Thread初始化内容'''
        threading.Thread.__init__(self)
        self.threadName = name
        self.people = people
        self.do = do

    # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
    def run(self):
        '''重写run方法'''
        print("开始线程: " + self.threadName)
        # 执行任务之前锁定线程
        self.lock.acquire()
        chiHuoGuo(self.people, self.do)  # 执行任务
        # 执行完之后,释放锁
        self.lock.release()
        print("结束线程: " + self.name)

print("yoyo请小伙伴开始吃火锅:!!!")
# 设置线程组
threads = []
# 创建新线程
thread1 = myThread("xiaoming", "Thread-1", "添加")
thread2 = myThread("xiaowang", "Thread-2", "吃掉")
# 添加到线程组
threads.append(thread1)
threads.append(thread2)
# 开启线程
for thread in threads:
    thread.start()
# 阻塞主线程,等子线程结束
for thread in threads:
    thread.join()
time.sleep(0.1)
print("退出主线程:吃火锅结束,结账走人")

运行结果:

yoyo请小伙伴开始吃火锅:!!!
开始线程: Thread-1
Fri Mar 15 08:36:39 2019 吃火锅的小伙伴:xiaoming
开始线程: Thread-2
Fri Mar 15 08:36:41 2019 xiaoming正在 添加 鱼丸
Fri Mar 15 08:36:42 2019 xiaoming正在 添加 鱼丸
Fri Mar 15 08:36:43 2019 xiaoming正在 添加 鱼丸
Fri Mar 15 08:36:43 2019 吃火锅的小伙伴:xiaoming
结束线程: Thread-1
Fri Mar 15 08:36:43 2019 吃火锅的小伙伴:xiaowang
Fri Mar 15 08:36:45 2019 xiaowang正在 吃掉 鱼丸
Fri Mar 15 08:36:47 2019 xiaowang正在 吃掉 鱼丸
Fri Mar 15 08:36:48 2019 xiaowang正在 吃掉 鱼丸
Fri Mar 15 08:36:48 2019 吃火锅的小伙伴:xiaowang
结束线程: Thread-2
退出主线程:吃火锅结束,结账走人

 递归锁:

#线程锁,多个锁时,需加递归锁
 
import threading
import time

def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num += 1
    lock.release()
    return num

def run2():
    print("grab the second part data")
    lock.acquire()
    global num2
    num2 += 1
    lock.release()
    return num2

def run3():
    lock.acquire()
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()
    print(res, res2)

num, num2 = 0, 0
lock = threading.RLock() #递归锁
for i in range(3):
    t = threading.Thread(target=run3)
    t.start()
while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)

运行结果:

grab the first part data
--------between run1 and run2-----
grab the second part data
1 1
grab the first part data
--------between run1 and run2-----
grab the second part data
2grab the first part data
--------between run1 and run2-----
 2
3grab the second part data
3 3

----all threads done---
3 3

6.案例

        在一个线程中,每秒循环输出当前的年月日时分秒;于此同时, 在另一个线程中,实现张三的姓名每2秒打印输出4次结束。注意: 都需要使用类和继承实现功能。

        多线程:Thread

'''
1.多线程
要求:
    在一个线程中,每秒循环输出当前的年月日时分秒;于此同时,在另一个线程中,实现张三的姓名每2秒打印输出4次结束。
    注意:都需要使用类和继承实现功能。
'''

import threading
import time

# 在第一个线程中,每秒循环输出当前的年月日时分秒
class Print_Time(threading.Thread):
    def run(self):
        while True:
            # 每隔1s获取当地时间并打印一次
            location_time = time.asctime(time.localtime(time.time()))
            print(location_time)
            # 每次延时1s
            time.sleep(1)

# 在第二个线程中,实现姓名每2秒打印输出4次结束
class Print_Name(threading.Thread):
    # 构造方法,继承threading.Thread,并实例化
    def __init__(self, name):
        # 继承父类的方法
        super(Print_Name, self).__init__()
        # 实例化对象属性
        self.name = name

    # 重写父类中的run方法
    def run(self):
        # 用for语句循环实现两秒内打印4次张三的名字后结束
        for i in range(4):
            print(self.name)
            # 每次延时0.5s,
            time.sleep(0.5)

def main():
    # 创建线程对象thread1,然后用start方法启动线程
    thread1 = Print_Time()
    thread1.start()
    # 创建线程对象thread2,传入参数,然后用start方法启动线程
    thread2 = Print_Name("张三")
    thread2.start()

if __name__ == '__main__':
    main()

        运行结果:

Thu Jan 20 23:08:40 2022
张三
张三
Thu Jan 20 23:08:41 2022
张三
张三
Thu Jan 20 23:08:42 2022
Thu Jan 20 23:08:43 2022
Thu Jan 20 23:08:44 2022
Thu Jan 20 23:08:45 2022
Thu Jan 20 23:08:47 2022
Thu Jan 20 23:08:48 2022

标签:20,Thread,Python,Jan,threading,线程,time,多线程
来源: https://blog.csdn.net/W_000/article/details/122607042

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有