参考:

python3多线程——官方教程中文版

python多线程-1

python多线程-2.1

python多线程-2.2

python多线程-3

python多线程-4


python中的多线程无法在多个核上同时进行,这是因为:

Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。

GIL是Python解释器设计的历史遗留问题,通常我们用的解释器是官方实现的CPython,要真正利用多核,除非重写一个不带GIL的解释器。

所以,在Python中,可以使用多线程,但不要指望能有效利用多核。如果一定要通过多线程利用多核,那只能通过C扩展来实现,不过这样就失去了Python简单易用的特点。

不过,也不用过于担心,Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响。


Thread类构造方法

Thread(group = None, target = None, name = None, args = (), kwargs = {})

  • group: 线程组,目前尚未实现,必须是None。

  • target:要执行的方法。

  • name:线程名。(默认是Thread-number)

  • args/kwargs:要传入方法的参数。

实例方法

  • isAlive():返回线程是否在运行。

  • get/setName:获取/设置线程名。

  • start():启动线程

  • is/setDaemon(bool):获取/设置是后台进程(默认是前台进程(False))。

    • 如果是后台进程,主线程执行过程中,后台线程也在进行,主线程执行完毕之后,后台线程不论成功与否,主线程和后台线程均停止。

    • 如果是前台线程,主线程执行过程中,前台线程也在执行,主线程执行完毕后,等待前台线程执行完成后,程序停止。

  • join():阻塞当前上下文环境的线程,知道调用此方法的线程终止或者到达指定的timeout(可选参数)。

创建线程的两种方法

  • 方法1:将想要执行的方法传给Thread类中的构造方法。

  • 方法2:定义一个新类继承Thread类,重写run方法。

# 创建线程的两种方法

# 第一种:将要执行的方法传给Thread的构造方法
import threading
import time def run(n):
time.sleep(1)
print(n) for i in range(5):
t = threading.Thread(target = run, args = (i,))
t.start() # 第二种,继承Thread类,重写run()方法 class Mythread(threading.Thread):
def __init__(self, arg):
threading.Thread.__init__(self)
# super().__init__(self)
self.arg = arg def run(self):
time.sleep(1)
print(self.arg) for i in range(5,10):
t = Mythread(i)
t.start()

setDeamon方法

设置是后台进程(True)还是前台进程(False)。(默认是False)

例题如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time class Mythread(threading.Thread):
def __init__(self, arg, name):
threading.Thread.__init__(self, name=name)
# super().__init__(self)
self.arg = arg def run(self):
time.sleep(3)
print(self.arg) thread = Mythread(10, 'TestThread') # thread.setDaemon(True)
thread.start() for i in range(2):
print(threading.current_thread().name + ': ', i)
# 判断子线程是不是存活
print(thread.name + ': ', thread.isAlive())
time.sleep(1)

输出:

MainThread:  0
TestThread: True
MainThread: 1
TestThread: True
10

在线程启动前,设置:

thread.setDaemon(True)

输出:

MainThread:  0
TestThread: True
MainThread: 1
TestThread: True

可以看到,子线程并没有完全进行完毕,因为这时主线程已经结束了,子线程也要跟着结束。

join方法

阻塞线程上下文,直到调用此方法的线程终止或到达指定的timeout,即使设置了setDeamon(True)的主线程也要等待子线程结束。

实例如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time class Mythread(threading.Thread):
def __init__(self, arg, name):
threading.Thread.__init__(self, name=name)
# super().__init__(self)
self.arg = arg def run(self):
time.sleep(1)
print(self.name + ': ', self.arg) thread = Mythread(10, 'TestThread') for i in range(5):
t = Mythread(i, 'Thread' + str(i))
t.start()
# t.join()

输出(比较乱,因为停顿1s后,所有的线程都在准备就绪的状态): ```python
Thread2: 2
Thread4: Thread1: Thread0: 0Thread3: 3 1
4

我们在每个线程的后面,用join方法进行阻塞,如下:

t.join()

输出:

Thread0:  0
Thread1: 1
Thread2: 2
Thread3: 3
Thread4: 4

Lock类、Rlock类

由于线程之间的随机调度:某个线程可能在执行n条后,CPU接着执行其他线程。为了防止多个线程同时操作一个内存资源时造成混乱,我们使用了锁。

例如,我们同时使用两个线程操作一个全局变量,如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading class Mythread(threading.Thread):
def __init__(self, name, i):
threading.Thread.__init__(self, name=name)
self.i = i def run(self): global count
for i in range(100000):
count -= self.i
count += self.i count = 10 t1 = Mythread('Thread' + str(1) + ': ', 100)
t2 = Mythread('Thread' + str(2) + ': ', 50)
t1.start()
t2.start()
t1.join()
t2.join() print('count = ', count)

在运行次数比较少的时候,可以输出正确答案,但是当循环次数变大之后,每次输出的结果就不一样了。

但是,当我们使用了Lock类之后,如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import threading
import time class Mythread(threading.Thread):
def __init__(self, name, i):
threading.Thread.__init__(self, name=name)
self.i = i def run(self): global count
for i in range(100000):
lock.acquire() # 获取锁
count -= self.i
count += self.i
lock.release() # 释放锁 count = 10
lock = threading.Lock()
t1 = Mythread('Thread' + str(1) + ': ', 100)
t2 = Mythread('Thread' + str(2) + ': ', 50)
t1.start()
t2.start()
t1.join()
t2.join() print('count = ', count)

Lock类与RLock类的区别。

这两种锁的主要区别是:在同一线程内,对RLock进行多次acquire()操作,程序不会阻塞。

  • threading.Lock() 加载线程的锁对象,是一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取

  • threading.RLock() 多重锁,在同一线程中可用被多次acquire。 如果使用RLock,那么acquire和release必须成对出现。

初识python多线程的更多相关文章

  1. Python导出Excel为Lua/Json/Xml实例教程(一):初识Python

    Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...

  2. Python开发【第一篇】:初识Python

    初识python 一.python简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解 ...

  3. python多线程学习记录

    1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start() ...

  4. python多线程编程

    Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...

  5. Python 多线程教程:并发与并行

    转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...

  6. python多线程

    python多线程有两种用法,一种是在函数中使用,一种是放在类中使用 1.在函数中使用 定义空的线程列表 threads=[] 创建线程 t=threading.Thread(target=函数名,a ...

  7. Python开发【第二篇】:初识Python

    Python开发[第二篇]:初识Python   Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏 ...

  8. python 多线程就这么简单(转)

    多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...

  9. python 多线程就这么简单(续)

    之前讲了多线程的一篇博客,感觉讲的意犹未尽,其实,多线程非常有意思.因为我们在使用电脑的过程中无时无刻都在多进程和多线程.我们可以接着之前的例子继续讲.请先看我的上一篇博客. python 多线程就这 ...

随机推荐

  1. Appium脚本(3):sendkey(封装capability)

    输入中文注意添加这个配置,否正中文输入不了desired_caps['unicodeKeyboard'] = "True"desired_caps['resetKeyboard'] ...

  2. precommit那些事儿

    一.使用背景 我们有将 lint 命令添加进 npm scripts 中,但是很多人在提交代码时都会忘记或者没有习惯去执行检查,结果就是导致不符合规范的代码被上传到远端代码仓库. 二.问题分析 我们可 ...

  3. spring security实现记住我下次自动登录功能

    目录 spring security实现记住我下次自动登录功能 一.原理分析 二.实现方式 2.1 简单实现方式 2.2 数据库实现方式 三.区分是密码登录还是rememberme登录 spring ...

  4. python基础(二)-- 列表、字典、集合、字符串操作

    4.列表: 基本操作: 索引 切片 追加 删除 长度 切片 循环 包含 import copy i=0 #persons=['dailaoban','xiekeng',['age',100,50],' ...

  5. [转] Win10插入U盘后双击无法打开,无法访问,显示设备未就绪;驱动哥帮你解决

    说起U盘,相信大家都不陌生. 这个不起眼的小东西在我们日常生活息息相关,一旦损坏可能就会造成一些不必要的麻烦. 最近驱动哥就收到了一大批用户关于U盘问题的相关咨询,一起来看看到底是什么情况吧! 据其中 ...

  6. python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)

    12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...

  7. Scratch编程:漂亮的时钟(九)

    “ 上节课的内容全部掌握了吗?反复练习了没有,编程最好的学习方法就是练习.练习.再练习.一定要记得多动手.多动脑筋哦~~” 01 — 游戏介绍 这节我们将绘制一个漂亮的.会走动时钟. 02 — 设计思 ...

  8. Unity性能优化-音频设置

    没想到Unity的音频会成为内存杀手,在实际的商业项目中,音频的优化必不可少. 1. Unity支持许多不同的音频格式,但最终它将它们全部转换为首选格式.音频压缩格式有PCM.ADPCM.Vorbis ...

  9. Java 哈希表

    public int firstUniqChar(String s){ int[] freq=new int[26]; for(int i=0;i<s.length();i++){ freq[s ...

  10. sql group by hour 按小时分组统计

    Time字段以小时分组统计 select datepart(hour,time) hour,count(1) count from table where Similarity<75 group ...