首页 > 其他分享 >【3.0】知识点小结(线程相关)

【3.0】知识点小结(线程相关)

时间:2023-06-26 17:56:07浏览次数:38  
标签:__ 知识点 name 线程 3.0 time print main

【3.0】知识点小结(线程相关)

【一】什么是线程

  • 进程

    • 资源单位
  • 线程

    • 执行单位
  • 将操作系统比喻成大的工厂

    • 进程相当于工厂里面的车间
    • 线程相当于车间里面的流水线

每一个进程必定自带一个线程

进程:资源单位

​ 起一个进程仅仅只是 在内存空间中开辟出一块独立的空间

线程:执行单位

​ 真正被CPU执行的其实是进程里面的线程,线程指的就是代码的执行过程,执行代码中所需要使用到的资源都找所在的进程索要

进程和线程都是虚拟单位,只是为了我们更加方便的描述问题

【二】为何要有线程

  • 开设进程

    • 申请内存空间 -- 耗资源
    • 拷贝代码 - 耗资源
  • 开设线程

    • 一个进程内可以开设多个线程
    • 在一个进程内开设多个线程无需再次申请内存空间及拷贝代码操作
  • 总结线程的优点

    • 减少了资源的消耗
    • 同一个进程下的多个线程资源共享

案例需求:开发一款文本编辑器

​ 获取用户输入的功能

​ 实时展示到屏幕的功能

​ 自动保存数据到硬盘的功能

针对上述功能进程合适还是线程合适?

​ 开三个线程更加合理

【三】开启线程的两种方式

开启线程不需要在main下面执行代码,直接书写即可

但是我们还是习惯性的将启动命令写在main下面

【1】方式一:直接调用

进程与线程的对比

# -*-coding: Utf-8 -*-
# @File : 01 开启线程的两种方式 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/24

from multiprocessing import Process
from threading import Thread
import time


def task(name):
    print(f'当前任务:>>>{name} 正在运行')
    time.sleep(3)
    print(f'当前任务:>>>{name} 结束运行')


def Thread_main():
    t = Thread(target=task, args=("dream",))
    # 创建线程的开销非常小,几乎代码运行的一瞬间线程就已经创建了
    t.start()
    '''
    当前任务:>>>dream 正在运行this is main process!
    this is main process!
    当前任务:>>>dream 结束运行
    '''


def Process_main():
    p = Process(target=task, args=("dream",))
    p.start()
    '''
    this is main process!
    当前任务:>>>dream 正在运行
    当前任务:>>>dream 结束运行
    '''


if __name__ == '__main__':
    Thread_main()
    # Process_main()
    print('this is main process!')

【2】方式二:继承父类

# -*-coding: Utf-8 -*-
# @File : 01 开启线程的两种方式 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/24

# 方式二
from multiprocessing import Process
from threading import Thread
import time


class MyThread(Thread):

    def __init__(self, name):
        # 重写了别人的方法,又不知道别人的方法里面有什么, 就调用父类的方法
        super().__init__()
        self.name = name

    # 定义 run 函数
    def run(self):
        print(f'{self.name} is running')
        time.sleep(3)
        print(f'{self.name} is ending')


def main():
    t = MyThread('dream')
    t.start()
    print(f'this is a main process')

    """
    dream is running
    this is a main process
    dream is ending
    """


if __name__ == '__main__':
    main()

【四】如何实现TCP服务端并发效果

【1】基础版1.0

服务端只能接待一个客户端

  • 客户端
# -*-coding: Utf-8 -*-
# @File : 02 如何实现客户端并发效果 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/24
from socket import *

# 不写参数:默认是TCP协议
# (1)创建客户端对象
client = socket()

# (2)绑定 IP PORT
# (2)建立链接桥梁 --(呼应客户端的 ip 和 port)
IP = '127.0.0.1'
PORT = 8082
client.connect((IP, PORT))

# (4)链接循环
while True:
    # (4.1)向服务端发数据
    msg_to_server = b'this is a message'
    client.send(msg_to_server)

    # 接受服务器返回的数据
    data_from_server = client.recv(1024)

    # (4.3)接收到客户端的信息
    msg_from_client = data_from_server.decode('utf-8')
    print(msg_from_client)

  • 服务端
# -*-coding: Utf-8 -*-
# @File : 02 如何实现客户端并发效果 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/24
from threading import Thread
from multiprocessing import Process
from socket import *

'''
服务端的三大特点:
    (1)要有固定的IP和PORT
    (2)24h不间断提供服务
    (3)能够支持并发
'''

# 不写参数:默认是TCP协议
# (1)创建服务器对象
server = socket()

# (2)建立链接桥梁 --(呼应客户端的 ip 和 port)
IP = '127.0.0.1'
PORT = 8082
server.bind((IP, PORT))

# (3)半连接池创建
server.listen(5)


# 正常版本
def normal_version():
    # (4)链接循环
    while True:
        # (4.1) 接受连接对象和 ip port
        conn, addr = server.accept()
        while True:
            # 捕获异常并抛出
            try:
                msg_from_client = conn.recv(1024)
                # (4.2)接受的信息为空时,会无限循环
                if len(msg_from_client) == 0:
                    break

                # (4.3)接收到客户端的信息
                msg_from_client = msg_from_client.decode('utf-8')
                print(msg_from_client)

                # (4.4)返回给客户端信息
                msg_to_client = msg_from_client.upper()
                msg_to_client = msg_to_client.encode('utf-8')
                conn.send(msg_to_client)

            except Exception as e:
                print(e)
                break
        # (4.5)关闭链接
        conn.close()


# 将接受处理数据部分封装成函数调用
def talk(conn):
    while True:
        # 捕获异常并抛出
        try:
            msg_from_client = conn.recv(1024)
            # (4.2)接受的信息为空时,会无限循环
            if len(msg_from_client) == 0:
                break

            # (4.3)接收到客户端的信息
            msg_from_client = msg_from_client.decode('utf-8')
            print(msg_from_client)

            # (4.4)返回给客户端信息
            msg_to_client = msg_from_client.upper()
            conn.send(msg_to_client)

        except Exception as e:
            print(e)
            break
    # (4.5)关闭链接
    conn.close()



if __name__ == '__main__':
    normal_version()

【2】升级版2.0

封装函数:启用多线程

  • 服务端
# -*-coding: Utf-8 -*-
# @File : 02 如何实现客户端并发效果 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/24
from threading import Thread
from multiprocessing import Process
from socket import *

'''
服务端的三大特点:
    (1)要有固定的IP和PORT
    (2)24h不间断提供服务
    (3)能够支持并发
'''

# 不写参数:默认是TCP协议
# (1)创建服务器对象
server = socket()

# (2)建立链接桥梁 --(呼应客户端的 ip 和 port)
IP = '127.0.0.1'
PORT = 8083
server.bind((IP, PORT))

# (3)半连接池创建
server.listen(5)


# 正常版本
def normal_version():
    # (4)链接循环
    while True:
        # (4.1) 接受连接对象和 ip port
        conn, addr = server.accept()
        while True:
            # 捕获异常并抛出
            try:
                msg_from_client = conn.recv(1024)
                # (4.2)接受的信息为空时,会无限循环
                if len(msg_from_client) == 0:
                    break

                # (4.3)接收到客户端的信息
                msg_from_client = msg_from_client.decode('utf-8')
                print(msg_from_client)

                # (4.4)返回给客户端信息
                msg_to_client = msg_from_client.upper()
                msg_to_client = msg_to_client.encode('utf-8')
                conn.send(msg_to_client)

            except Exception as e:
                print(e)
                break
        # (4.5)关闭链接
        conn.close()


# 将接受处理数据部分封装成函数调用
def talk(conn):
    while True:
        # 捕获异常并抛出
        try:
            msg_from_client = conn.recv(1024)
            # (4.2)接受的信息为空时,会无限循环
            if len(msg_from_client) == 0:
                break

            # (4.3)接收到客户端的信息
            msg_from_client = msg_from_client.decode('utf-8')
            print(msg_from_client)

            # (4.4)返回给客户端信息
            msg_to_client = msg_from_client.upper()
            msg_to_client = msg_to_client.encode('utf-8')
            conn.send(msg_to_client)

        except Exception as e:
            print(e)
            break
    # (4.5)关闭链接
    conn.close()


# 多线程版本
def threading_version(conn):
    t = Thread(target=talk, args=(conn,))
    t.start()


# 多进程版本
def process_version(conn):
    p = Process(target=talk, args=(conn,))
    p.start()


def main_t():
    # (4)链接循环
    while True:
        # (4.1) 接受连接对象和 ip port
        conn, addr = server.accept()
        threading_version(conn)


def main_p():
    # (4)链接循环
    while True:
        # (4.1) 接受连接对象和 ip port
        conn, addr = server.accept()
        process_version(conn)


if __name__ == '__main__':
    main_t()
  • 客户端
# -*-coding: Utf-8 -*-
# @File : 02 如何实现客户端并发效果 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/24
from socket import *

# 不写参数:默认是TCP协议
# (1)创建客户端对象
client = socket()

# (2)绑定 IP PORT
# (2)建立链接桥梁 --(呼应客户端的 ip 和 port)
IP = '127.0.0.1'
PORT = 8083
client.connect((IP, PORT))

# (4)链接循环
while True:
    # (4.1)向服务端发数据
    msg_to_server = b'this is a message'
    client.send(msg_to_server)

    # 接受服务器返回的数据
    data_from_server = client.recv(1024)

    # (4.3)接收到客户端的信息
    msg_from_client = data_from_server.decode('utf-8')
    print(msg_from_client)

【五】线程对象的 join 方法

# -*-coding: Utf-8 -*-
# @File : 03 线程对象的 join 方法 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread
import time


def task(name):
    print(f'the task {name} is beginning')
    time.sleep(3)
    print(f'the task {name} is ending')


def main():
    t = Thread(target=task, args=('dream',))
    t.start()

    # 主线程等待子进程结束之后再运行
    t.join()

    print(f'the task is main task')


if __name__ == '__main__':
    main()
    
    # the task dream is beginning
    # the task dream is ending
    # the task is main task

【六】同一个进程下的多个线程之间数据是共享的

# -*-coding: Utf-8 -*-
# @File : 04 同一个进程下的多个线程之间数据是共享的 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25

from threading import Thread
import time

money = 999


def task():
    global money
    money = 99
    print(f'task中的money:>>>>{money}')


def main():
    print(f'子进程之前的money:>>>>{money}')
    t = Thread(target=task)
    t.start()
    print(f'子进程之后的money:>>>>{money}')


if __name__ == '__main__':
    main()

    # 子进程之前的money:>>>>999
    # task中的money:>>>>99
    # 子进程之后的money:>>>>99

【七】线程对象属性及其他方法

同一个进程下的进程号相同

# -*-coding: Utf-8 -*-
# @File : 05 线程对象属性及其他方法 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread
import time, os


def task():
    print(f'this is a task PID {os.getpid()}')


def main():
    t = Thread(target=task)
    t.start()
    print(f'this is a main PID {os.getpid()}')


if __name__ == '__main__':
    main()
    
    # this is a task PID 6496
    # this is a main PID 6496

current_thread

获取当前进程的名字

# -*-coding: Utf-8 -*-
# @File : 05 线程对象属性及其他方法 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread, active_count, current_thread
import time, os


def task():
    # 获取当前线程的名字
    print(f'this is a task name {current_thread().name}')


def main():
    t = Thread(target=task)
    t.start()
    print(f'this is a main name {current_thread().name}')


if __name__ == '__main__':
    main()

    # this is a task name Thread-1
    # this is a main name MainThread

active_count

统计当前活跃的线程数

  • 这里统计的线程数 2 个
    • 可能已经有一个子线程已经死了
# -*-coding: Utf-8 -*-
# @File : 05 线程对象属性及其他方法 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread, active_count, current_thread
import time, os


def task():
    # 获取当前线程的名字
    print(f'this is a task name {current_thread().name}')


def main():
    t = Thread(target=task)
    t1 = Thread(target=task)
    t.start()
    t1.start()
    # 统计当前活跃的线程数
    print(f'this is a main process active_process {active_count()}')
    print(f'this is a main name :>>>> {current_thread().name}')


if __name__ == '__main__':
    main()

    # this is a task name Thread-1
    # this is a task name Thread-2
    # this is a main process active_process 1
    # this is a main name :>>>> MainThread
  • 这里统计的活跃进程数是 3 个
    • 让我们第一个子进程晚一点死
# -*-coding: Utf-8 -*-
# @File : 05 线程对象属性及其他方法 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread, active_count, current_thread
import time, os


def task():
    # 获取当前线程的名字
    print(f'this is a task name {current_thread().name}')
    time.sleep(1)


def main():
    t = Thread(target=task)
    t1 = Thread(target=task)
    t.start()
    t1.start()
    # 统计当前活跃的线程数
    print(f'this is a main process active_process {active_count()}')
    print(f'this is a main name :>>>> {current_thread().name}')


if __name__ == '__main__':
    main()

    # this is a task name Thread-1
    # this is a task name Thread-2
    # this is a main process active_process 3
    # this is a main name :>>>> MainThread

【八】守护线程

【1】主线程死亡,子线程未死亡

主线程结束运行后不会马上结束,而是等待其他非守护子线程结束之后才会结束

如果主线程死亡就代表者主进程也死亡,随之而来的是所有子线程的死亡

# -*-coding: Utf-8 -*-
# @File : 06 守护线程 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25

from threading import Thread
import time


def task(name):
    print(f'当前 {name} is beginning')
    time.sleep(2)
    print(f'当前 {name} is ending')


def main():
    t = Thread(target=task, args=('dream',))
    t.start()

    print(f' this is main process')


if __name__ == '__main__':
    main()

    # 当前 dream is beginning 
    # this is main process
    # 当前 dream is ending

【2】主线程死亡,子线程也死亡

# -*-coding: Utf-8 -*-
# @File : 06 守护线程 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25

from threading import Thread
import time


def task(name):
    print(f'当前 {name} is beginning')
    time.sleep(2)
    print(f'当前 {name} is ending')


def main():
    t = Thread(target=task, args=('dream',))
    
    # 开启守护线程
    t.daemon = True
    t.start()

    print(f' this is main process')


if __name__ == '__main__':
    main()

    # 当前 dream is beginning 
    # this is main process

【3】迷惑性例子

# -*-coding: Utf-8 -*-
# @File : 06 守护线程 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25

from threading import Thread
from multiprocessing import Process
import time


def foo():
    print(f' this is foo begin')
    time.sleep(1)
    print(f' this is foo end')


def func():
    print(f' this is func begin')
    time.sleep(3)
    print(f' this is func end')


def main():
    t1 = Thread(target=foo)
    t2 = Thread(target=func)
    t1.daemon = True
    t1.start()
    t2.start()

    print(f' this is main')


if __name__ == '__main__':
    main()
    
    #  this is foo begin
    #  this is func begin
    #  this is main
    #  this is foo end
    #  this is func end

分析

​ t1 是守护线程,会随着主线程的死亡而死亡

​ 当多线程开启时,主线程运行,开启子线程

​ 再开启主线程

​ 主线程结束后会等待非守护子线程结束,所以需要等待3s,等待func结束运行

​ 所以执行顺序是 子线程1---子线程2---主线程---子线程1结束---子线程2结束

【九】线程的互斥锁

【1】问题

所有子线程都会进行阻塞操作,导致最后的改变只是改了一次

# -*-coding: Utf-8 -*-
# @File : 07 线程的互斥锁 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread
import time

money = 100


def task():
    global money

    # 模拟获取到车票信息
    temp = money

    # 模拟网络延迟
    time.sleep(2)

    # 模拟购票
    money = temp - 1


def main():
    t_list = []
    for i in range(100):
        t = Thread(target=task)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()

    # 所有子线程结束后打印 money
    print(money)


if __name__ == '__main__':
    main()

    # 99

【2】解决办法

在数据发生变化的地方进行加锁处理

# -*-coding: Utf-8 -*-
# @File : 07 线程的互斥锁 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread, Lock
import time

money = 100
# 生成锁
mutex = Lock()


def task():
    global money

    # 数据发生改变之前加锁
    mutex.acquire()

    # 模拟获取到车票信息
    temp = money

    # 模拟网络延迟
    time.sleep(0.6)

    # 模拟购票
    money = temp - 1

    # 数据发生改变后解锁
    mutex.release()


def main():
    t_list = []
    for i in range(100):
        t = Thread(target=task)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()

    # 所有子线程结束后打印 money
    print(money)


if __name__ == '__main__':
    main()

    # 0

【十】GIL全局解释器锁

In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple
native threads from executing Python bytecodes at once. This lock is necessary mainly

because CPython’s memory management is not thread-safe. (However, since the GIL
exists, other features have grown to depend on the guarantees that it enforces.)

结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势
  • Python解释器其实有多个版本

    • Cpython
    • Jpython
    • Pypypython
  • 但是普遍使用的都是Cpython解释器

  • Cpython 解释器中 GIL 是一把互斥锁,用来阻止同一个进程下的多个线程的同时进行

    • 同一个进程下的多个线程无法利用这一优势?
      • Python的多线程是不是一点用都没有?
  • 因为在 Cpython 中的内存管理不是线程安全的

    • ps:内存管理(垃圾回收机制)
      • 应用计数

      • 标记清除

      • 分代回收

1.GIL 不是python的特点而是Cpython解释器的特点

2.GIL 保证解释器级别的数据的安全

3.GIL会导致同一个进程下的多个线程的无法同时进行即无法利用多核优势

4.针对不同的数据还是需要加不同的锁处理

5.解释型语言的通病:同一个进程下的多个线程无法利用多核优势

【十一】GIL锁与普通互斥锁的区别

【1】普通版 1.0

当睡了 0.1s 后

所有线程都去抢那把 GIL 锁住的数据,当所有子线程都抢到后再去修改数据就变成了 99

# -*-coding: Utf-8 -*-
# @File : 08 GIL锁 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread, Lock
import time

mutex = Lock()

money = 100


def task():
    global money
    temp = money
    time.sleep(0.1)
    money -= temp


def main():
    t_list = []
    for i in range(100):
        t = Thread(target=task)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()
    print(money)


if __name__ == '__main__':
    main()
    
    # 99

【2】升级版 2.0

谁先抢到谁就先处理数据

# -*-coding: Utf-8 -*-
# @File : 08 GIL锁 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread, Lock
import time

mutex = Lock()

money = 100


def task():
    global money
    temp = money
    money -= temp


def main():
    t_list = []
    for i in range(100):
        t = Thread(target=task)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()
    print(money)


if __name__ == '__main__':
    main()
    
    # 0

【3】终极版 3.0

自动加锁并解锁

子线程启动 , 后先去抢 GIL 锁 , 进入 IO 自动释放 GIL 锁 , 但是自己加的锁还没解开 ,其他线程资源能抢到 GIL 锁,但是抢不到互斥锁

最终 GIL 回到 互斥锁的那个进程上,处理数据

# -*-coding: Utf-8 -*-
# @File : 08 GIL锁 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from threading import Thread, Lock
import time

mutex = Lock()

money = 100


def task():
    global money

    # 自动执行 加锁 再解锁操作
    with mutex:
        temp = money
        time.sleep(0.1) # 只要进入 IO 会自动释放 GIL 锁
        money -= temp


def main():
    t_list = []
    for i in range(100):
        t = Thread(target=task)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()
    print(money)


if __name__ == '__main__':
    main()

【十二】同一个进程下的多线程无法利用多核优势,是不是就没用了

【1】多线程是否有用要看情况

  • 单核
    • 四个任务(IO密集型/计算密集型)
  • 多核
    • 四个任务(IO密集型/计算密集型)

【2】计算密集型

一直处在计算运行中

  • 每个任务都需要 10s

    • 单核

      • 多进程:额外消耗资源

      • 多线程:减少开销

    • 多核

      • 多进程:总耗时 10s
      • 多线程:总耗时 40s+
# -*-coding: Utf-8 -*-
# @File : 09 验证多进程与多线程应用场景 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25
from multiprocessing import Process
from threading import Thread
import time, os


def work():
    res = 0
    for i in range(1, 100000000):
        res *= i


def main_t():
    p_list = []
    # 获取当前CPU运行的个数
    print(os.cpu_count())
    start_time = time.time()
    for i in range(12):
        p = Process(target=work)
        p.start()
        p_list.append(p)

    for p in p_list:
        p.join()

    print(f'总耗时:>>>{time.time() - start_time}')

    # 8
    # 总耗时:>>>28.140103101730347


def main_p():
    t_list = []
    # 获取当前CPU运行的个数
    print(os.cpu_count())
    start_time = time.time()
    for i in range(12):
        t = Thread(target=work)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()

    print(f'总耗时:>>>{time.time() - start_time}')

    # 8
    # 总耗时:>>>63.330037117004395


if __name__ == '__main__':
    # main_t()
    main_p()

【3】IO密集型

存在多个 IO 阻塞切换操作

  • 每个任务都需要 10s
    • 多核
      • 多进程:相对浪费资源
      • 多线程:更加节省资源
# -*-coding: Utf-8 -*-
# @File : 09 验证多进程与多线程应用场景 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/25


from multiprocessing import Process
from threading import Thread
import time, os


def work():
    time.sleep(2)


def main_t():
    p_list = []
    # 获取当前CPU运行的个数
    print(os.cpu_count())
    start_time = time.time()
    for i in range(400):
        p = Process(target=work)
        p.start()
        p_list.append(p)

    for p in p_list:
        p.join()

    print(f'总耗时:>>>{time.time() - start_time}')

    # 8
    # 总耗时:>>>36.23059678077698


def main_p():
    t_list = []
    # 获取当前CPU运行的个数
    print(os.cpu_count())
    start_time = time.time()
    for i in range(400):
        t = Thread(target=work)
        t.start()
        t_list.append(t)

    for t in t_list:
        t.join()

    print(f'总耗时:>>>{time.time() - start_time}')

    # 8
    # 总耗时:>>>2.1423909664154053


if __name__ == '__main__':
    main_t()
    # main_p()

【4】小结

  • 多线程和多进程都有各自的优势

  • 通常项目都是多进程下面开多进程

    • 这样既可以利用多核又可以节省资源消耗

标签:__,知识点,name,线程,3.0,time,print,main
From: https://www.cnblogs.com/dream-ze/p/17506346.html

相关文章

  • 【4.0】知识点小结(线程进阶)
    【4.0】知识点小结(线程进阶)【一】什么是死锁与递归锁死锁是指两个或多个进程,在执行过程中,因争夺资源而造成了互相等待的一种现象。即两个或多个进程持有各自的锁并试图获取对方持有的锁,从而导致被阻塞,不能向前执行,最终形成僵局。在这种情况下,系统资源利用率极低,系统处于一种......
  • 保证线程安全的10个小技巧
    前言对于从事后端开发的同学来说,线程安全问题是我们每天都需要考虑的问题。线程安全问题通俗的讲:主要是在多线程的环境下,不同线程同时读和写公共资源(临界资源),导致的数据异常问题。比如:变量a=0,线程1给该变量+1,线程2也给该变量+1。此时,线程3获取a的值有可能不是2,而是1。线程3这不......
  • SimpleDateFormat 线程不安全!使用DateTimeFormatter
    1、报错原因:(1)、SimpleDateFormat是线程不安全的(2)、代码想把格林威治时间转换成yyyy-MM-ddHH:mm:ss报错Exceptioninthread:java.lang.NumberFormatException:Forinputstring:""类似下图的错误: 2、解决方案:使用DateTimeFormatter//时间转换DateTimeFor......
  • 浅析 Jetty 中的线程优化思路
    作者:vivo互联网服务器团队-WangKe本文介绍了Jetty中ManagedSelector和ExecutionStrategy的设计实现,通过与原生select调用的对比揭示了Jetty的线程优化思路。Jetty设计了一个自适应的线程执行策略(EatWhatYouKill),在不出现线程饥饿的情况下尽量用同一个线程侦测I/O事......
  • Linux多线程09-互斥锁
    为避免线程更新共享变量时出现问题,可以使用互斥量(mutex是mutualexclusion的缩写)来确保同时仅有一个线程可以访问某项共享资源。可以使用互斥量来保证对任意共享资源的原子访问。互斥量有两种状态:已锁定(locked)和未锁定(unlocked)。任何时候,至多只有一个线程可以锁定该互斥量。试......
  • Linux多线程10-死锁
    有时,一个线程需要同时访问两个或更多不同的共享资源,而每个资源又都由不同的互斥量管理。当超过一个线程加锁同一组互斥量时,就有可能发生死锁。两个或两个以上的进程在执行过程中,因争夺共享资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状......
  • Linux多线程12-生产者和消费者模型
    一个最简单的生产者消费者模型/*生产者消费者模型(粗略版)*/#include<stdio.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>structNode{intnum;structNode*next;};//头节点structNode*head=NULL;void*producer(void*arg){......
  • Linux多线程11-读写锁
    当有一个线程已经持有互斥锁时,互斥锁将所有试图进入临界区的线程都阻塞住。但是考虑一种情形,当前持有互斥锁的线程只是要读访问共享资源,而同时有其它几个线程也想读取这个共享资源,但是由于互斥锁的排它性,所有其它线程都无法获取锁,也就无法读访问共享资源了,但是实际上多个线程同时......
  • Linux多线程14-信号量
    信号量的类型sem_tintsem_init(sem_t*sem,intpshared,unsignedintvalue);初始化信号量参数:-sem:信号量变量地址-pshared:0用在线程间,非0用在进程间-value:信号量中的值intsem_destroy(sem_t*sem);释放资......
  • Linux多线程13-条件变量
    上节代码存在的问题:生产者已经没有数据了,消费者还在while循环判断是否有数据,浪费资源没有数据了应该通知生产者生产,生产好了通知消费者消费这就需要条件变量pthread_cond_tintpthread_cond_init(pthread_cond_t*restrictcond,constpthread_con......