进程,多线程,线程同步


这是一篇根据自己查阅资料,基于自己理解写的关于进程,线程的文章。文章结构也是我思考方式的一个流程,如果有错误的地方,感谢指出。

1. 进程和线程

定义上说,进程是资源分配(CPU和内存)分配的基本单位,线程是程序执行的最小单元。根据我自己的理解,一个py文件就是一个进程,run这个py文件后,就产生了一个线程,称为主线程。也就是说,一个进程一定包含一个主线程。

资料上说,一个进程可以包含多个线程,这些线程是并发的,但在只有一个CPU的情况下,并发并不是严格意义上的同时执行,而是轮流做,比如线程1做0.01s,线程2再0.01s,线程1再做0.02s,从人的观测角度来说,会觉得线程1和2是同时执行的,实际上不是这样。

2. 为什么会有多线程

当系统中有一个很长的任务时,别的任务需要等它做完了才能开始做。假设有任务1:将一个word文件存储成pdf,这个过程需要10s;任务2: 在微信上的对话框上输入:你好,这个过程需要2s。如果等任务1做完,再做任务2,从用户的角度来说,在键盘上打了"你好"以后,需要等待10s才有响应,看起来就像是电脑死机了,这样的体验是很差的。

由此可以总结出多线程的目的1:为了让另一个任务也早点开始,早点响应。

如果任务1做1s,任务2做1s,任务1再做1s…这样轮流着来,这样任务2的响应就很快,但完成任务1和任务2的总时间是一样的。

2.1 那有没有对任务1和任务2使用多线程(轮流做)的时间,比任务1和任务2按顺序做的时间短的情况呢?

有的。

  1. 当任务1或任务2中有time.sleep()这样的代码时,系统是不会调用CPU的,也就是不会使用到资源,那么CPU就可以去忙下一个任务啦,也就是一遍让任务1等,一遍做任务2,总时间就会减少。

  2. 有多个CPU,就可以实现真正的同时处理多个任务。

3. 根据上面对多线程的解释,有疑惑的点吗?

有的(自问自答)。

3.1 前面提到,任务1做1s,任务2做1s,再做任务1时,怎么保证是从上次中断的地方继续做的呢?

需要记录中断的指令 -> 指令指针
记录内存的位置 -> 堆栈指针寄存器

3.2 如果两个线程都要对同一个变量进行操作。假设线程1是从某人的账户里取钱,线程2是向某人的账户里存钱,那操作不就乱套了吗?

是的,这就需要线程同步来解决这种冲突。

当线程想要对同一个共享变量进行操作时,必须先申请一把锁,申请到了才能操作共享变量,操作完后再释放锁。在操作过程中,别的线程会发现该变量已经上锁,就只能等待锁释放后,抢锁,抢到了才能操作该共享变量。

举一个例子,你和另一个人都想上厕所,但是厕所有门没锁,那可能会出现一种情况:正在上厕所的你,门被别人打开,是个想要和你一起上厕所的变态。但如果厕所有门有锁,那另一个人必须得等到你上完厕所,开锁出来了,才可以进去使用这个厕所,使用前也要锁上门,防止别人进来。

不知道理解的对不对,感觉线程同步感觉回到了最初的起点,所有的线程必须都按顺序执行,那就相当于没有多线程。但也许在掌握了线程的操作以后,也许就能实现线程1和线程2并行,但同时又和线程3同步的高端操作了吧。

4. Python中多线程的实现

是根据菜鸟的这个指南学习的。

python中多线程的实现是通过threading这个模块,它提供的方法有:

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

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

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

这个 j o i n ( ) join() join() 的功能一开始没有太理解,搜索了一些别的资料后理解如下:

当一个进程启动时,会默认产生一个主线程,我们使用Threading模块创建的都是子线程。默认情况下,主线程在执行完自己的任务后,就会退出,此时子线程会继续执行自己的任务。也就是说,主线程的结束并不会影响子线程。

但有的时候我们会将创建的子线程 t t t 设为守护线程,具体方法是:

t.setDaemon(True)
t.start()
(顺序不能反)

守护线程:一种特殊子线程,当主线程所有非守护线程(即普通子线程)结束时,守护线程立刻结束,不管该做的指令有没有做完。

但如果希望在所有子线程结束前,主线程一直挂起,那么可以就使用 t . j o i n ( ) t.join() t.join() 来达到该目的。也就是主线程会一直等待调用过 j o i n ( ) join() join() 函数的子线程都结束后,再结束。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值