进程和线程的区别和多线程操作

简介: 进程和线程的区别和多线程操作

一、进程和线程的区别

readme文件

进程:
简单的说:进程就是运行着的程序。
我们写的python程序(或者其他应用程序比如画笔、qq等),运行起来,就称之为一个进程
在windows下面打开任务管理器,里面显示了当前系统上运行着的进程
线程:
而系统中每个进程里面至少包含一个 **线程** 。
线程是操作系统创建的,每个线程对应一个代码执行的数据结构,保存了代码执行过程中的重要的状态信息。
没有线程,操作系统没法管理和维护 代码运行的状态信息。
所以没有创建线程之前,操作系统是不会执行我们的代码的。
我们前面写的Python程序,里面虽然没有创建线程的代码,但实际上,当Python解释器程序运行起来(成为一个进程),
OS就自动的创建一个线程,通常称为主线程,在这个主线程里面执行代码指令。
当解释器执行我们python程序代码的时候,我们的代码就在这个主线程中解释执行。
join通常用于 主线程把任务分配给几个子线程,等待子线程完成工作后,需要对他们任务处理结果进行再处理。
就好像一个领导把任务分给几个员工,等几个员工完成工作后,他需要收集他们提交的报告,进行后续处理。
这种情况,主线程必须子线程完成才能进行后续操作,所以join就是 等待参数对应的线程完成,才返回。
每个线程在 操作共享数据对象之前,都应该 申请获取操作权,也就是 调用该 共享数据对象对应的锁对象的acquire方法。
如果线程A 执行如下代码,调用acquire方法的时候
bankLock.acquire()

二、简单线程理解代码

sup_test.py

# coding=utf-8
"""
    @Project :pachong-master 
    @File    :sup_test.py
    @Author  :gaojs
    @Date    :2022/7/10 17:06
    @Blogs   : https://www.gaojs.com.cn
"""
from threading import Thread
from time import sleep
# 定义一个函数,作为新线程执行的入口函数
def thread_test(arg1, arg2):
    print('子线程 开始')
    print(f'线程函数参数是:{arg1}, {arg2}')
    sleep(5)
    print('子线程 结束')
# 创建Thread 类的实例
thread = Thread(
    # target 参数 指定 新线程要执行的函数
    # 注意,这里指定的函数对象只能写一个名字,不能后面加括号,
    # 如果加括号就是直接在当前线程调用执行,而不是在新线程中执行了
    target=thread_test,
    # 如果 新线程函数需要参数,在 args里面填入参数
    # 注意参数是元组, 如果只有一个参数,后面要有逗号,像这样 args=('参数1',)
    args=('参数1', '参数2')
)
# 执行start 方法,就会创建新线程,
# 并且新线程会去执行入口函数里面的代码。
# 这时候 这个进程 有两个线程了。
# 注意,上面的代码只是创建了一个Thread实例对象, 但这时,新的线程还没有创建。
# 要创建线程,必须要调用 Thread 实例对象的 start方法
thread.start()
# 主线程的代码执行 子线程对象的join方法,
# 就会等待子线程结束,才继续执行下面的代码
thread.join()
print('主线程结束')

三、多线程

mutil_sup.py

# coding=utf-8
"""
    @Project :pachong-master 
    @File    :multi_sup_test.py
    @Author  :gaojs
    @Date    :2022/7/10 17:21
    @Blogs   : https://www.gaojs.com.cn
"""
from threading import Thread, Lock
from time import sleep
# 现在我们程序代码中,有多个线程,并且在这个几个线程中都会去调用 deposit,就有可能同时操作这个bank对象,
# 就有可能出一个线程覆盖另外一个线程的结果的问题。
#
# 这时,可以使用 threading库里面的锁对象 Lock 去保护
bank = {
    'gaojs': 0
}
bankLock = Lock()
# 定义一个函数,作为新线程执行的入口函数
def after_money(theadidx, amount):
    # 操作共享数据前,申请获取锁
    bankLock.acquire()
    balance = bank['gaojs']
    # 执行一些任务,耗费了0.1秒
    sleep(0.1)
    bank['gaojs'] = balance + amount
    # print(bank['gaojs'])
    print(f'第 {theadidx} 个子线程结束')
    # 操作完共享数据后,申请释放锁
    bankLock.release()
theadlist = []
for idx in range(10):
    thread = Thread(
        target=after_money,
        args=(idx, 1)
    )
    thread.start()
    # 把线程对象都存储到 threadlist中
    theadlist.append(thread)
for thread in theadlist:
    thread.join()
print('主线程结束')
print(f'最后我们的账号余额为 {bank["gaojs"]}')
print(bank)

image.png

相关文章
聊聊python多线程与多进程
为什么要使用多进程与多线程呢? 因为我们如果按照流程一步步执行任务实在是太慢了,假如一个任务就是10秒,两个任务就是20秒,那100个任务呢?况且cpu这么贵,时间长了就是浪费生命啊!一个任务比喻成一个人,别个做高铁,你做绿皮火车,可想而知!接下来我们先看个例子:
|
7天前
|
数据采集 存储 C++
单线程 vs 多进程:Python网络爬虫效率对比
本文探讨了Python网络爬虫中的单线程与多进程应用。单线程爬虫实现简单,但处理速度慢,无法充分利用多核CPU。而多进程爬虫通过并行处理提高效率,更适合现代多核架构。代码示例展示了如何使用代理IP实现单线程和多进程爬虫,显示了多进程在效率上的优势。实际使用时还需考虑代理稳定性和反爬策略。
单线程 vs 多进程:Python网络爬虫效率对比
|
7天前
|
安全 Linux 编译器
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)(下)
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)
18 0
|
7天前
|
安全 C语言 C++
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)(中)
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)
16 0
|
7天前
|
Linux 调度 C语言
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)(上)
从C语言到C++_40(多线程相关)C++线程接口+线程安全问题加锁(shared_ptr+STL+单例)
15 0
|
8天前
|
缓存 Java 编译器
Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字(二)
加锁其实是一个比较低效的操作,因为加锁就可能涉及到阻塞等待。
20 1
|
8天前
|
安全 Java 编译器
Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字(一)
下面就是一个线程不安全的例子。该代码中创建了一个counter变量,同时分别创建了两个线程t1和t2,让这两个线程针对同一个counter令其自增5w次。
24 0
|
8天前
|
编解码 安全 算法
Java多线程基础-18:线程安全的集合类与ConcurrentHashMap
如果这些单线程中的集合类确实需要在多线程中使用,该怎么办呢?思路有两个: 最直接的方式:使用锁,手动保证。如多个线程修改ArrayList对象,此时就可能有问题,就可以给修改操作进行加锁。但手动加锁的方式并不是很方便,因此标准库还提供了一些线程安全的集合类。
27 4
|
8天前
|
安全 Java 容器
Java 多线程系列Ⅶ(线程安全集合类)
Java 多线程系列Ⅶ(线程安全集合类)
|
8天前
|
设计模式 安全 Java
Java 多线程系列Ⅳ(单例模式+阻塞式队列+定时器+线程池)
Java 多线程系列Ⅳ(单例模式+阻塞式队列+定时器+线程池)