【python】进阶--->并发编程之线程(一)

发布时间:2023年12月19日

在介绍进程之前,我先给大家补充一些 Queue()进程池Pool 的概念

一、Queue()

Queue.put(item, block, timeout)
Queue.put_nowait(item)===>Queue.put(item, False)

Queue.get(block, timeout):获取队列中的一条数据,然后将它从队列中移除
?如果block使用默认值True,且没有设置timeout秒,消息队列如果为空,那么程序将会被阻塞,直到从消息队列中读到消息为止
?如果block使用默认值True,设置timeout秒,则会等待timeout秒,若没有在这个时间内读取到数据,则会抛出异常queue.empty.
?如果block设置为False,消息队列为空,则会立即抛出异常queue.empty
Queue.get_nowait()===>Queue.get(False)

Queue.empty() : 如果队列为空,返回True Queue.full():如果队列满了,返回True
Queue.qsize() : 返回当前队列包含的消息数量

import multiprocessing
import time
import random
 
# q = multiprocessing.Queue(3)  # 括号内表示最多接收的消息数
# q.put('消息1')
# q.put('消息2')
# q.put('消息3')
# q.put('消息4', block=False)  # 当队列满了之后,会阻塞,不能写入
# print(q.get())
# print(q.get())
# print(q.get())
 
 
# try:
#     print(q.put('消息4'))
# except:  # 捕捉异常
#     print('消息队列为空')
# else:
#     print('没有错误')
 
# if not q.empty():
#     print(q.get())
 
def write(q):
    for value in ['a', 'b', 'c']:
        q.put(value)
        time.sleep(random.random())
 
 
def read(q):
    while True:
        if not q.empty():
            value = q.get()
            print('获取%s' % value)
            time.sleep(random.random())
        else:
            break
 
 
if __name__ == '__main__':
    q = multiprocessing.Queue()
    pw = multiprocessing.Process(target=write, args=(q, ))
    pr = multiprocessing.Process(target=read, args=(q, ))
    pw.start()
    pw.join()
    pr.start()
    pr.join()
    print('全部读写完成')

二、进程池Pool

multiprocessing.Pool() : 括号内可以传入最大可接受的进程数
常用函数 :
apply_async(func,args, kwargs) : 使用非阻塞方式调用func(并行执行, 阻塞 :必须等待上一个进程退出才能执行下一个进程),args和kwargs为传递给func的参数.
close() : 关闭进程池,不在接收新的进程 。
terminate() : 不管任务是否完成,立即终止.
join() : 主进程阻塞,等待子进程的退出,必须在调用close或者terminate后使用.

进程池中的Queue
如果要使用pool创建进程,就需要使用multiprocessing.Manager()中的Queue()
# import multiprocessing
# import time
#
#
# def run(f):
#     time.sleep(1)
#     return f*f
#
#
# if __name__ == '__main__':
#     test1 = [1, 2, 3, 4, 5, 6]
#     print('循序执行:')
#     s = time.time()
#     for i in test1:
#         print(run(i))
#     e1 = time.time()
#     print('循序执行时间:', e1-s)
#
#     print('并发:')
#     pool = multiprocessing.Pool(5)  # 创建拥有5条进程数量的进程池
#     # map(函数,可迭代对象)
#     # 循环将可迭代对象的值传给第一个参数的函数执行
#     r1 = pool.map(run, test1)
#     pool.close()  # 关闭进程池,不再接收新的进程
#     # pool对象调用join方法会等待所有子进程执行完毕
#     # 但是调用之前必须调用close方法,表示不再接收新的进程
#     pool.join()
#     e2 = time.time()
#     print('并发执行时间:', e2-e1)
#     print(r1)
 
 
# 进程池中的进程通信
import multiprocessing, os, random, time
 
 
def read(q):
    print('read启动(%s),父进程为(%s)' % (os.getpid(), os.getppid()))
    for i in range(q.qsize()):
        print('read从Queue中获取到消息:', q.get())
 
 
def write(q):
    print('write启动(%s),父进程为(%s)' % (os.getpid(), os.getppid()))
    for i in ['a', 'b', 'c', 'd']:
        q.put(i)
        print('write往Queue中写入消息:', i)
 
 
if __name__ == '__main__':
    print('主进程(%s)启动' % os.getpid())
    q = multiprocessing.Manager().Queue()  # 使用Manager中的 Queue
    pool = multiprocessing.Pool()
    pool.apply_async(write, (q,))
    time.sleep(1)
    pool.apply_async(read, (q,))
    pool.close()
    pool.join()
    print('主进程(%s)结束' % os.getpid())

三、线程

线程是进程的一个实体,是cpu调度分配基本单元.
线程自己基本上不拥有系统的资源,只拥有一点在运行中必不可少的资源,但是他和同属一个进程的其他线程共享进程所拥有的全部资源
例如:
进程 : 在一台电脑上运行的多个qq
线程 : 一个qq中的多个聊天窗口

区别 :

  • 一个进程至少有一个线程,线程的划分尺度小于进程(资源比进程少)

  • 进程在执行的过程中拥有独立的内存单元,而多个线程共享内存

  • 线程不能独立执行,必须依存在进程中

threading.Thread(group, target, name, args, kwargs)
group : 线程组,目前没有用
target : 要执行的函数
name : 线程名,默认Thread-N
args/kwargs : 要传给函数的参数
常用方法:
is_alive() : 返回线程是否在运行
get/setName(name) : 获取/设置线程名
start() : 线程准备就绪,等待cpu调度
is/setDaemon(bool) : 获取/设置是守护线程(默认不是(False))
?如果是守护线程,主线程执行过程中,守护线程也在执行,主线程执行完毕后,不论守护线程是否成功执行完毕,都要停止.
?如果不是守护线程,主线程执行过程中,它也在执行,主线程执行完毕后,会等待该线程也执行完毕,才会结束程序.
join(timeout) : 阻塞当前上下文环境的线程,直到调用该方法的线程终止或者到达指定的timeout停止阻塞.

import time
import threading
 
 
def test():
    print('hello')
    time.sleep(1)
 
 
class MyThread(threading.Thread):
    def run(self):
        for i in range(5):
            time.sleep(1)
            print('hello')
 
 
if __name__ == '__main__':
    s = time.time()
    # for i in range(5):
    #     test()
    # e = time.time()
    # print('耗时:', e-s)
    #
    # for i in range(5):
    #     t = threading.Thread(target=test)
    #     t.start()
    # e2 = time.time()
    # print('耗时:', e2-e)
    t = MyThread()
    t.start()
    e = time.time()
    print('耗时:', e-s)

四、主线程和子线程

当一个程序启动时,一个单独的线程运行,就是主线程.新创建的线程,称为子线程.

python主线程和子线程的结束顺序
?主线程退出后子线程的运行状态依赖于它所在的进程,如果进程没有退出的话子线程依然正常运行.如果进程退出了,那么所有的线程都会退出,所以子线程也会退出.
?主线程退出,进程会等待所有子线程执行完毕后才结束
进程启动后会默认产生一个主线程,默认情况下主线程创建的子线程都不是守护线程(setDaemon(False)).因此主线程结束后,子线程会继续执行,进程会等待所有子线程执行完毕后才结束.
?主线程结束后进程不等待守护线程完毕,立即结束 当设置一个线程为守护线程时,此线程所属进程不会等待此线程运行结束,进程会立即结束.

在这里插入图片描述
t是守护线程,t2不是守护线程.因此,进程会等待t2执行完毕,而不会等待t完毕就会结束进程.

import time, threading
 
def test1():
    for i in range(10):
        time.sleep(1)
        print('test1----')
 
# def test2():
#     for i in range(5):
#         time.sleep(1)
#         print('test2----')
 
 
if __name__ == '__main__':
    print('主线程开始运行')
    t = threading.Thread(target=test1)
    # t2 = threading.Thread(target=test2)
    t.setDaemon(True)  # 设置为守护线程
    t.start()
    # t2.start()
    print('主线程结束')

主线程等待子线程完成后结束
在线程中使用join进行阻塞,会等待调用join的线程执行完毕后才会执行后面的内容.

关于Python线程(一)的介绍今天就到这里啦,后续我会为大家介绍线程(二)的相关知识哦~
关注我,带你领略Python的风采~😍😍😍

文章来源:https://blog.csdn.net/m0_75141643/article/details/135068655
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。