一、线程

Python 中为我们提供了两个模块来创建线程。

  • _thread
  • threading

thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python 中不能再使用"thread" 模块。为了兼容性,Python 将 thread 重命名为 “_thread”。

相对 _thread 模块来说, threading 模块更加高级也更加常用。

多线程

创建多线程步骤:

  1. 导入线程库
  2. 创建任务函数
  3. 创建线程对象
  4. 启动线程

实例:

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学习笔记(九)——线程与进程的更多相关文章

  1. python学习笔记12 ----线程、进程

    进程和线程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进程里的 ...

  2. python学习笔记11 ----线程、进程、协程

    进程.线程.协程的概念 进程和线程是操作系统中两个很重要的概念,对于一般的程序,可能有若干个进程,每一个进程有若干个同时执行的线程.进程是资源管理的最小单位,线程是程序执行的最小单位(线程可共享同一进 ...

  3. python学习笔记之线程、进程和协程(第八天)

    参考文档: 金角大王博客:http://www.cnblogs.com/alex3714/articles/5230609.html 银角大王博客:http://www.cnblogs.com/wup ...

  4. Python学习笔记九

    Python学习笔记之九 为什么要有操作系统 管理硬件,提供接口. 管理调度进程,并且将多个进程对硬件的竞争变得有序. 操作系统发展史 第一代计算机:真空管和穿孔卡片 没有操作系统,所有的程序设计直接 ...

  5. python学习笔记09--线程、进程

    本节内容 一.进程与线程的概念 1.1进程 1.2线程 1.3进程与线程的区别 二.线程 2.1启一个线程 2.2线程的2种调用方式 2.3 join 2.4 守护线程Daemon 2.5线程锁 2. ...

  6. python学习道路(day10note)(线程,进程)

    1.计算机的发展史 看alex的博客吧,了解一下可以了 2.线程与GIL简介 #线程 #一道单一的指令的控制流,寄生在进程中 #单一进程里的多个线程是共享数据的 #多个线程涉及修改共享数据的时候需要枷 ...

  7. python 学习笔记九 队列,异步IO

    queue (队列) 队列是为线程安全使用的. 1.先入先出 import queue #测试定义类传入队列 class Foo(object): def __init__(self,n): self ...

  8. Python学习笔记9-多线程和多进程

    一.线程&进程 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程, ...

  9. python学习笔记——multiprocessing 多进程组件 进程池Pool

    1 进程池Pool基本概述 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量时间,如果操作的对象数目不大时,还可以直接适用Process类动态生成 ...

  10. python 学习笔记 - Queue & Pipes,进程间通讯

    上面写了Python如何创建多个进程,但是前面文章中创建的进程都是哑巴和聋子,自己顾自己执行,不会相互交流.那么如何让进程间相互说说话呢?Python为我们提供了一个函数multiprocessing ...

随机推荐

  1. Ng ML笔记

    目录 一.线性回归 1,假设函数.代价函数,梯度下降 2,特征处理 3,代价函数和学习速率 4,特征和多项式回归 5,正规方程 二.逻辑回归(Logistic Regression,LR) 1,假设函 ...

  2. idea教程--如何使用码云管理代码

    1.安装Gitee插件 由于我已经安装过了,请参加白色背景的图 2.idea配置git 3.配置码云账号 4.配置ssh秘钥(注意:如果之前安装git已经配置过了可以跳过此步) (1) 生成SSH秘钥 ...

  3. LeetCode-023-合并K个升序链表

    合并K个升序链表 题目描述:给你一个链表数组,每个链表都已经按升序排列. 请你将所有链表合并到一个升序链表中,返回合并后的链表. 示例说明请见LeetCode官网. 来源:力扣(LeetCode) 链 ...

  4. 矩池云 | 教你如何使用GAN为口袋妖怪上色

    在之前的Demo中,我们使用了条件GAN来生成了手写数字图像.那么除了生成数字图像以外我们还能用神经网络来干些什么呢? 在本案例中,我们用神经网络来给口袋妖怪的线框图上色. 第一步: 导入使用库 fr ...

  5. MATLAB菜鸟入门笔记【作图章】

    1.函数标签[legend]         http://blog.csdn.net/wangcj625/article/details/6287735/

  6. ajax 无刷新页面登录

    1:页面代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  7. tensorflow core 核心目标依赖图

    Tensorflow的核心代码在core模块中,56w行的代码量让人望而生畏,熟悉了bazel工具之后,发现BUILD文件是理清代码结构的很好的资源,但使用bazel query语法提取出来//ten ...

  8. ESXI 虚拟化误删除管理端口Management Network (vmk0),导致无法访问后台解决方案

    按F2开启控制台shell,启用后返回.按Alt+F1打开终端. 输入 esxcfg-vmknic -a -i 192.168.1.10 -n 255.255.255.0 "Manageme ...

  9. 10、mysql的调优

    mysql的调优 调优的最终目的:节省系统资源.提高响应速度下面从6个维度对mysql进行优化. 第一步:对服务器的参数进行调优 通过show profile命令分析,如果sql语句在执行过程中等待时 ...

  10. 01 简介 如何高效的学习Java

    JavaSE 千寻简学习笔记 简介 TIOBE:编程语言排行榜 官网:https://hellogithub.com/report/tiobe/ 如何高效的学习Java 多写(代码)多写(笔记)多写( ...