2016/1/2 Python中的多线程(1):线程初探
---恢复内容开始---
新年第一篇,继续Python。
先来简单介绍线程和进程。
计算机刚开始发展的时候,程序都是从头到尾独占式地使用所有的内存和硬件资源,每个计算机只能同时跑一个程序。后来引进了一些机制来改进这种调用方法,包括流水线,多进程。我们开始并发执行程序,每个程序交替地被处理器调用,再极高的频率下,你会认为这些程序是在同时执行的,这也就是并发技术。用操作系统来管理并发,将程序读到内存中,然后被操作系统调用开始,它的生命周期就开始了。而每个程序的执行,都是用进程的方式执行,每个进程有自己的地址空间、内存、数据栈及别的什么东西。对于任何一个以进程方式执行的程序,都好似独占了全部的硬件资源。每个进程都有从地址0开始的虚拟内存地址。也就是说,进程是一定意义的抽象。然后操作系统管理所有的进程,给它们分配分时运行的时间。进程之间通过一定的进程间交互手段来通信,不能直接共享信息。
那什么是线程?
线程常常被称为轻量级进程,跟进程有些相似,不同的是所有的线程都运行在同一个进程中,共享同样的运行环境,有同样的地址空间、数据栈空间。可以认为在一个进程里,有很多并行执行的线程。
线程有开始,顺序执行和结束三个部分。它有一个自己的指令指针,记录自己运行到什么地方。线程的运行可能被抢占或者暂时挂起,让其他线程运行,这种方式叫做让步。
线程间由于共享了同样的数据空间,所以可以很方便地共享数据和通讯,但是,有一个问题是多个线程同时访问同一片数据,由于顺序不同,可能数据结果会不一致,产生了所谓的竞态条件。
总的来说,线程是在一个程序里设置的几个并发运行的过程,让几件事情可以同时执行。
Python中使用线程
Python的代码由Python虚拟机控制,可以通过全局解释器锁GIL来控制,也可以直接用一些模块来实现我们的需求。接下来主要来介绍thread和threading模块。thread模块一般不推荐使用,因为它在主线程退出时,其他线程若没有结束,还没有清除就退出了,而threading模块确保所有的重要的子线程都退出后才会结束进程。
默认情况下,Python对线程的支持是打开的。在交互模式下尝试导入thread模块没有错误就表示可用。
>>> import thread
>>>
如果出现了导入错误,那么应该重新编译Python解释器才能运行,这里不作说明。
先来看一个没有多线程支持例子:
这里用了time模块的sleep()函数,里面输入一个浮点的参数,表示睡眠的秒数,意味着程序将被挂起这段时间。
from time import sleep, ctime def loop0():
print 'start loop 0 at: %s' % ctime()
sleep(4)
print 'loop 0 done at: %s' % ctime() def loop1():
print 'start loop 1 at: %s' % ctime()
sleep(2)
print 'loop 1 done at: %s' % ctime() def main():
print 'starting at: %s' % ctime()
loop0()
loop1()
print 'all Done at: %s' % ctime() if __name__ == '__main__':
main()
>>>
starting at: Sat Jan 02 21:17:48 2016
start loop 0 at: Sat Jan 02 21:17:48 2016
loop 0 done at: Sat Jan 02 21:17:52 2016
start loop 1 at: Sat Jan 02 21:17:52 2016
loop 1 done at: Sat Jan 02 21:17:54 2016
all Done at: Sat Jan 02 21:17:54 2016
可以看到,程序毫无疑问的顺序执行了,但是,我们用sleep()挂起的时间并没有意义了。
所以,让我们看一下用了线程之后的方法:
import thread
from time import sleep, ctime def loop0():
print 'start loop 0 at: %s' % ctime()
sleep(4)
print 'loop 0 done at: %s' % ctime() def loop1():
print 'start loop 1 at: %s' % ctime()
sleep(2)
print 'loop 1 done at: %s' % ctime() def main():
print 'starting at: %s' % ctime()
thread.start_new_thread(loop0,())
thread.start_new_thread(loop1,())
sleep(6)
print 'all Done at: %s'% ctime() if __name__ == '__main__':
main()
结果会是这样的
>>>
starting at: Sat Jan 02 21:23:58 2016
start loop 0 at: Sat Jan 02 21:23:58 2016
start loop 1 at: Sat Jan 02 21:23:58 2016
loop 1 done at: Sat Jan 02 21:24:00 2016
loop 0 done at: Sat Jan 02 21:24:02 2016
all Done at: Sat Jan 02 21:24:04 2016
可以看到,这一次loop1和loop0在程序开始后4秒就结束了,只是我们多了一句sleep(6),让整个程序最后还是跑了6秒,加这一句,是防止主线程结束后子线程也就退出了,导致根本没有执行完,但是这种方法实在是很愚蠢,我们最后程序还是跑了6秒才能结束,如果我们有一次并不知道子进程什么时候结束,比如说从键盘读到一条命令后结束,那么该如何写这样的语句呢。接下来我会介绍这种方法,我们先来看看thread这个模块在此处干了什么。
我们调用了thread的一个方法start_new_thread(funciton, args kwargs=None),这个方法的作用是产生一个新线程,在新线程中用指定的参数和可选的kwargs来调用这个函数。这是一个很简单的线程机制。
接下来用锁来杜绝在主线程中使用sleep()函数:
import thread
from time import ctime, sleep loops = [4, 2] def loop(nloop, nsec, lock):
print 'start loop%s at: %s\n' % (nloop, ctime()),
sleep(nsec)
print 'loop%s done at: %s\n' % (nloop, ctime()),
lock.release() def main():
print 'starting at: %s\n' % ctime(),
locks = []
nloops = range(len(loops)) for i in nloops:
lock = thread.allocate_lock()
lock.acquire()
locks.append(lock) for i in nloops:
thread.start_new_thread(loop, (i, loops[i], locks[i])) for i in nloops:
while locks[i].locked():
pass print 'all DONE at: %s\n' %ctime(), if __name__ == '__main__':
main()
显示结果是这样的:
>>>
starting at: Sat Jan 02 21:55:30 2016
start loop0 at: Sat Jan 02 21:55:30 2016
start loop1 at: Sat Jan 02 21:55:30 2016
loop1 done at: Sat Jan 02 21:55:32 2016
loop0 done at: Sat Jan 02 21:55:34 2016
all DONE at: Sat Jan 02 21:55:34 2016
大家可以看到我用了一种很抽风的方式使用print语句,至于为什么不用基本的方法,各位可以看一下用原来的方法输出结果是怎样的。
这里面,我们用了用了thread.allocate_lock()函数来创建一个锁对象,然后将它存到一个锁的列表里去,每次都得调用acquire()函数来获得锁,也就是把锁锁上,锁上后,通过一个锁的列表,在循环里,每个线程分配到自己的锁,然后一起执行。在线程结束的时候,我们需要解锁。
为什么不在创建锁的过程中创建进程呢?有两个原因,一个是我们希望每个线程都是同步开始的,要让它们几乎同时开始。另一个是每次获取锁会花一定的时间,如果线程退出的太快,可能锁还没有获取,线程就结束了。
所以我们需要分配锁,获得锁,释放锁,来实现进程的同步。
今天先写到这里,下一次再说明threading的使用,那时候,将不需要考虑这些锁的问题。
2016/1/2 Python中的多线程(1):线程初探的更多相关文章
- 2016/1/3 Python中的多线程(2):threading模块
之前提了Python多线程的一点使用,今天介绍更好的threading模块,它提供了Thread类和一些比较好用的同步机制. 先介绍Thread类 threading模块中的Thread类有很多thr ...
- python中的多线程【转】
转载自: http://c4fun.cn/blog/2014/05/06/python-threading/ python中关于多线程的操作可以使用thread和threading模块来实现,其中th ...
- python中的多线程
一个程序可以理解为一个进程,这个进程有其代号,可以依据这个代号将其杀死. 一个进程肯定有且只有一个主线程,他可以有很多子线程. 运行一个任务如果可以有许多子线程同时去做,当然会提高效率. 但是,在py ...
- Python中的多线程编程,线程安全与锁(二)
在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...
- python中的多线程和多进程
一.简单理解一下线程和进程 一个进程中可有多个线程,线程之间可共享内存,进程间却是相互独立的.打比方就是,进程是火车,线程是火车厢,车厢内人员可以流动(数据共享) 二.python中的多线程和多进程 ...
- python中的进程、线程(threading、multiprocessing、Queue、subprocess)
Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...
- python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享
Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...
- Qt中的多线程与线程池浅析+实例
1. Qt中的多线程与线程池 今天学习了Qt中的多线程和线程池,特写这篇博客来记录一下 2. 多线程 2.1 线程类 QThread Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一 ...
- Python中的多线程编程,线程安全与锁(一)
1. 多线程编程与线程安全相关重要概念 在我的上篇博文 聊聊Python中的GIL 中,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作. 以下是简单回顾,详细介绍请直接看聊聊P ...
随机推荐
- DPDK L2fwd 源码阅读
代码部分 /* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2016 Intel Corporation */ #include ...
- 使用JProfiler做性能分析过程
供自己记录一下,也分享给大家使用JProfiler的过程(感谢教我使用这个工具的大佬),整个博客比较粗糙,希望对大家有帮助 1.首先安装好JProfiler,打开eclipse,右键你所要分析的项目, ...
- Unity如何判断网络状态?
根据Application.internetReachability来判断网络状态 NetworkReachability.NotReachable 网络不可用 NetworkReachability ...
- Android之自定义View学习(一)
Android之自定义View学习(一) Canvas常用方法: 图片来源 /** * Created by SiberiaDante on 2017/6/3. */ public class Bas ...
- es6 ...展开运算符
展开运算符,目前应用在数组上,对象展开运算符,将在es7 提案 1.两个对象连接返回新的对象 let a = {aa:'aa'} let b = {bb:'bb'} let c = {...a,. ...
- 学术诚信与职业道德——《构建之法》P384~391读后感
程序本身没有伦理和职业道德, 但是程序员和软件企业要有,因为程序员明白伦理道德的存在. 对于刚刚经历被不负责队友抛下的经历,对此很有感触,软件工程师除了遵守任务做事,也要考虑道德上.责任上的事情. 就 ...
- paperOne基于java web的简易四则运算出题网站
项目成员:张金生 张政 需求概要 1.运算数均为正整数 2.包含的运算符有+,-,*,/ 3.除法运算结果为整除运算 4.批量生成题目并判题 核心功能分析 1.题目生成——java后端 题目生 ...
- canvas制作原生的百分比圆形比例等
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 性能分析_linux服务器CPU_Load Average
CPU度量Load Average 1. 概念介绍 1.1 Linux系统进程状态 在linux中,process有以下状态: runnable (就绪状态):blocked waiting fo ...
- QTime的本质上是一个int,QDateTime本质上是一个qint64
研究这个问题的起因发现使用<=比较时间的不准确,所以怀疑是一个浮点数(Delphi里的time就是一个浮点数).结果却发现是一个int class Q_CORE_EXPORT QTime { e ...