---恢复内容开始---

新年第一篇,继续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):线程初探的更多相关文章

  1. 2016/1/3 Python中的多线程(2):threading模块

    之前提了Python多线程的一点使用,今天介绍更好的threading模块,它提供了Thread类和一些比较好用的同步机制. 先介绍Thread类 threading模块中的Thread类有很多thr ...

  2. python中的多线程【转】

    转载自: http://c4fun.cn/blog/2014/05/06/python-threading/ python中关于多线程的操作可以使用thread和threading模块来实现,其中th ...

  3. python中的多线程

    一个程序可以理解为一个进程,这个进程有其代号,可以依据这个代号将其杀死. 一个进程肯定有且只有一个主线程,他可以有很多子线程. 运行一个任务如果可以有许多子线程同时去做,当然会提高效率. 但是,在py ...

  4. Python中的多线程编程,线程安全与锁(二)

    在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...

  5. python中的多线程和多进程

    一.简单理解一下线程和进程 一个进程中可有多个线程,线程之间可共享内存,进程间却是相互独立的.打比方就是,进程是火车,线程是火车厢,车厢内人员可以流动(数据共享) 二.python中的多线程和多进程 ...

  6. python中的进程、线程(threading、multiprocessing、Queue、subprocess)

    Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...

  7. python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享

    Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...

  8. Qt中的多线程与线程池浅析+实例

    1. Qt中的多线程与线程池 今天学习了Qt中的多线程和线程池,特写这篇博客来记录一下 2. 多线程 2.1 线程类 QThread Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一 ...

  9. Python中的多线程编程,线程安全与锁(一)

    1. 多线程编程与线程安全相关重要概念 在我的上篇博文 聊聊Python中的GIL 中,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作. 以下是简单回顾,详细介绍请直接看聊聊P ...

随机推荐

  1. ps -aux 命令下的前几行内容解释 与 top命令下的前几行内容解释

    系统进程分为5种不同的状态: R(运行):正在运行或在运行队列中等待 S(中断):休眠中,在等待某个条件的形成或接受到信号 D(不可中断):收到信号不唤醒和不可运行.进程必须等待直到有中断发生 Z(僵 ...

  2. Python入门:参数传递方式

    这是关于Python的第5篇文章,主要介绍下参数传递方式和如何设计自己的函数. (一) 本篇主要介绍2种参数传递方式. 位置参数 调用函数时,根据函数定义的参数位置来传递参数. def right_t ...

  3. ORA-06530: 引用未初始化的组合 ;

    select * FROM TABLE(fun_test_1) : ORA-06530: 引用未初始化的组合ORA-06512: 在 "PCISS.FUN_TEST_1", lin ...

  4. call()方法和apply()方法

    最近又遇到了JacvaScript中的call()方法和apply()方法,而在某些时候这两个方法还确实是十分重要的,那么就让我总结这两个方法的使用和区别吧. 1. 每个函数都包含两个非继承而来的方法 ...

  5. mysql 数据到 导入导出 总结

    数据库数据的导入和导出受secure_file_priv配置项影响#限制导入导出,null时无法进行数据的导入导出,空时不限制,设置了目录则只能对该目录下的文件进行导入导出show variables ...

  6. 使用Fiddler后谷歌浏览器访问https不安全

    今天初次接触java爬虫,师兄给了一个软件加一个demo,软件是Fiddler,在网上找资料稍微学习了一下,自己一顿乱配...然后gg,谷歌浏览器访问https协议时都提示不安全,“您的链接不是一个私 ...

  7. maven执行"mvn clean package" 命令报错

    昨天利用mvn打包,执行程序'mvn clean package' 命令,发现打包失败 问题描述 具体看代码 发信tomcat下的log 清除不掉.为什么呢?忽然想起来我的项目服务还起着,于是我把服务 ...

  8. Netty简单使用

    目录 丢弃服务器 DiscardServerHandler DiscardServer 测试 应答服务器 时间服务器 TimeServerHandler TimeClient TimeClientHa ...

  9. HDU4641_K-string

    若它的一个子串出现的次数不少于K次,那么这个子串就是一个K-string. 现给出原串,每次可以向该串后面添加一个字符或者询问当前有多少个不同的K-string. 在线添加查询,解法直指SAM. 其实 ...

  10. POJ1430

    这个题目初看上去是一个排列组合题,而实际上……也是一个排列组合题. 题目描述是: Description The Stirling number of the second kind S(n, m) ...