python学习笔记(九)——线程与进程
一、线程
Python 中为我们提供了两个模块来创建线程。
- _thread
- threading
thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python 中不能再使用"thread" 模块。为了兼容性,Python 将 thread 重命名为 “_thread”。
相对 _thread 模块来说, threading 模块更加高级也更加常用。
多线程
创建多线程步骤:
- 导入线程库
- 创建任务函数
- 创建线程对象
- 启动线程
实例:
import threading,time
def task():
for i in range(1,11):
time.sleep(1)
print(threading.current_thread().name,end="")
print(":output >%d"%i)
print(time.ctime())
# 创建两个线程
pt1=threading.Thread( target=task )
pt2=threading.Thread( target=task )
# 输出线程名
print(threading.current_thread().name)
# 启动线程
pt1.start()
pt2.start()
pt1.join()
pt2.join()
print(time.ctime())
输出:
Sat Mar 14 16:07:12 2020
MainThread
Thread-2:output >1
Thread-1:output >1
Thread-1Thread-2:output >2
:output >2
Thread-1Thread-2:output >3
:output >3
Thread-1Thread-2:output >4
:output >4
Thread-1:output >5
Thread-2:output >5
Thread-1Thread-2:output >6
:output >6
Thread-2:output >7
Thread-1:output >7
Thread-2Thread-1:output >8
:output >8
Thread-2:output >9
Thread-1:output >9
Thread-1:output >10
Thread-2:output >10
Sat Mar 14 16:07:22 2020
可以看到一共用了10秒时间,两个线程都完成了自己的任务。
使用 threading.Thread( )
创建线程时,可以传入六个参数,比如线程名 name,任务函数参数 args等。
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
其中,如name、daemon等参数除了在创建线程时指定以外,还可以通过对象调用函数设置。 pt.setName()、pt.setDaemon()。
线程同步
在多线程中会常会发生多个线程同时访问同一个资源的情况,造成线程不安全。而我们要求线程对临界资源的操作是必须是原子操作,因此我们可以通过线程锁来实现线程安全。
使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法进行加锁和解锁。
lock=threading.RLock() # 创建一个锁
lock.acquire() # 加锁
lock.release() # 解锁
把每次只允许一个线程操作的数据,放到 acquire 和 release 方法之间进行操作。
全局解释器锁GIL
在非python环境中,单核情况下,同时只能有一一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少核,同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。
GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一 一个。拿不到通行证的线程,就不允许进入CPU执行。GIL 只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操作cpu,只能利用GIL保证同一-时间只能有- -个线程拿到数据。而在pypy和ipython中是没有GIL的。
所以,在Python中,可以使用多线程,但不要指望能有效利用多核。不过,也不用过于担心,Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响
二、进程
使用多进程同样可以完成多线程的工作,我们将之前的多线程程序改成多进程程序。
import multiprocessing
import time
def task():
for i in range(1,11):
time.sleep(1)
print(multiprocessing.current_process().name,__name__,end="")
print(":output >%d"%i)
if __name__=="__main__":
print(time.ctime())
p1=multiprocessing.Process(target=task)
p2=multiprocessing.Process(target=task)
p1.start()
p2.start()
p1.join()
p2.join()
print(time.ctime())
输出:
Sat Mar 14 17:25:31 2020
Process-1 __mp_main__:output >1
Process-2 __mp_main__:output >1
Process-1 __mp_main__:output >2
Process-2 __mp_main__:output >2
Process-1 __mp_main__:output >3
Process-2 __mp_main__:output >3
Process-1 __mp_main__:output >4
Process-2 __mp_main__:output >4
Process-1 __mp_main__:output >5
Process-2 __mp_main__:output >5
Process-1 __mp_main__:output >6
Process-2 __mp_main__:output >6
Process-1 __mp_main__:output >7
Process-2 __mp_main__:output >7
Process-1 __mp_main__:output >8
Process-2 __mp_main__:output >8
Process-1 __mp_main__:output >9
Process-2 __mp_main__:output >9
Process-1 __mp_main__:output >10
Process-2 __mp_main__:output >10
Sat Mar 14 17:25:41 2020
进程池
通过进程池 pool 可以批量的创建大量的进程。
import multiprocessing
import os
import time
def task(i):
print("线程%d 执行: pid=%s"%(i,os.getpid()))
time.sleep(1)
return i
def back(n):
print("任务%d已完成"%n)
if __name__=="__main__":
mypool=multiprocessing.Pool(5) # 线程池大小
for i in range(1,21): # 20个线程任务
mypool.apply_async(func=task,args=(i,))
mypool.close()
mypool.join()
apply_async()
会等待线程池中有空闲时依次执行线程任务。其中,callback 参数是回调函数。
进程池中回调函数callback作用是:进程池中任何一个任务一旦处理完了,就立即告知主进程,主进程则调用一个函数去处理该结果,它可以用来接收进程任务的返回值,判断其执行的结果。
输出结果:
线程1 执行: pid=12372
线程2 执行: pid=11236
线程3 执行: pid=15144
线程4 执行: pid=8332
线程5 执行: pid=16732
线程6 执行: pid=12372
任务1已完成
线程7 执行: pid=11236
任务2已完成
线程8 执行: pid=15144
任务3已完成
线程9 执行: pid=8332
任务4已完成
线程10 执行: pid=16732
任务5已完成
线程11 执行: pid=12372
任务6已完成
线程12 执行: pid=11236
任务7已完成
线程13 执行: pid=15144
任务8已完成
线程14 执行: pid=8332
任务9已完成
线程15 执行: pid=16732
任务10已完成
线程16 执行: pid=12372
任务11已完成
线程17 执行: pid=11236
任务12已完成
线程18 执行: pid=15144
任务13已完成
线程19 执行: pid=8332
任务14已完成
线程20 执行: pid=16732
任务15已完成
任务16已完成
任务17已完成
任务18已完成
任务19已完成
任务20已完成
需要注意的是,在使用线程池时应注意将pool.close()
先于 pool.join()
调用。因为 join() 会让主进程阻塞等待子进程全部执行完之后再执行,close() 的作用是关闭pool,使其不在接受新的(主进程)任务。所以,两个顺序可不能颠倒了。
python学习笔记(九)——线程与进程的更多相关文章
- python学习笔记12 ----线程、进程
进程和线程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进程里的 ...
- python学习笔记11 ----线程、进程、协程
进程.线程.协程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进 ...
- python学习笔记之线程、进程和协程(第八天)
参考文档: 金角大王博客:http://www.cnblogs.com/alex3714/articles/5230609.html 银角大王博客:http://www.cnblogs.com/wup ...
- Python学习笔记九
Python学习笔记之九 为什么要有操作系统 管理硬件,提供接口. 管理调度进程,并且将多个进程对硬件的竞争变得有序. 操作系统发展史 第一代计算机:真空管和穿孔卡片 没有操作系统,所有的程序设计直接 ...
- python学习笔记09--线程、进程
本节内容 一.进程与线程的概念 1.1进程 1.2线程 1.3进程与线程的区别 二.线程 2.1启一个线程 2.2线程的2种调用方式 2.3 join 2.4 守护线程Daemon 2.5线程锁 2. ...
- python学习道路(day10note)(线程,进程)
1.计算机的发展史 看alex的博客吧,了解一下可以了 2.线程与GIL简介 #线程 #一道单一的指令的控制流,寄生在进程中 #单一进程里的多个线程是共享数据的 #多个线程涉及修改共享数据的时候需要枷 ...
- python 学习笔记九 队列,异步IO
queue (队列) 队列是为线程安全使用的. 1.先入先出 import queue #测试定义类传入队列 class Foo(object): def __init__(self,n): self ...
- Python学习笔记9-多线程和多进程
一.线程&进程 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程, ...
- python学习笔记——multiprocessing 多进程组件 进程池Pool
1 进程池Pool基本概述 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态生成 ...
- python 学习笔记 - Queue & Pipes,进程间通讯
上面写了Python如何创建多个进程,但是前面文章中创建的进程都是哑巴和聋子,自己顾自己执行,不会相互交流.那么如何让进程间相互说说话呢?Python为我们提供了一个函数multiprocessing ...
随机推荐
- 换行符号(\r\n)的历史
文章来源:https://cloud.tencent.com/developer/article/1730918 \r\n与\n是有区别的. 如果要通用的则是\r\n,因为有些编辑器它不认\n &qu ...
- weblogic集群自动批量化补丁升级
转至:http://blog.itpub.net/28833846/viewspace-2726722/ 一.前言介绍 Weblogic是一种基于J2EE架构的中间件,用于开发.集成.部署和管理大型分 ...
- C#实现抢红包算法
二倍均值法(公平版) 发出一个固定金额的红包,由若干个人来抢,需要满足哪些规则? 1.所有人抢到金额之和等于红包金额,不能超过,也不能少于. 2.每个人至少抢到一分钱. 3.要保证所有人抢到金额的几率 ...
- 使用Logseq构建GTD系统
2021-05-08: 1.0版本初步完成,待完善已完成任务回顾 2021-05-10: 1.1版本完成,修改不重要不紧急为将来清单,且新增每周回顾 前言 最近在阅读<小强升职记>,感觉里 ...
- git命令新建远程分支并推送,切换远程地址
最近记性不好,老是忘记操作命令,记录下一下新建远程分支和切换.删除远程地址的命令: 1.查看当前分支: git branch 2.查看所有分支:git branch -a 3.切换分支:git ch ...
- pycharm实用常用快捷键
我们在实用pycharm时候,可以使用一些快捷键来帮助我们写代码. 1 alt + enter 快速导包,在需要导入包时候可以使用这个快捷键: 2 alt + 1 可以快速打开或者关闭左侧projec ...
- JAVA 线上问题排查方法
CPU 磁盘 内存 GC问题 网络 线上故障主要会包括cpu.磁盘.内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍. 同时例如jstack.jma ...
- PF4J使用
PF4J是一个Java轻量级的插件框架,可以实现动态加载,执行,卸载外部插件(支持jar以及zip),具体可以看官网:https://pf4j.org/. 本文例子基于Github地址:https:/ ...
- NET程序的代码混淆、加壳与脱壳
通常我们通过代码混淆.加密的形式达到软件保护的目的.在Web开发里我们接触过的可能就是JS代码加密了,可以通过对JS代码进行混淆.加密从而实现对核心JS代码的保护.如果没有接触过的可以在这里简单了解一 ...
- linux的一些sao东西
1.sys命令的目录 /usr/include/asm-generic