原文:http://codingpy.com/article/python-201-a-tutorial-on-threads/

创建多线程

创建多线程主要有2种方式。

  • 使用threading.Thread函数
  • 继承threading类

1. 使用threading.Thread函数

import threading

def tom(number):
print threading.currentThread().getName()
print number if __name__ == "__main__":
number = ["zero", "one", "two", "three", "four"]
sex = ["man", "woman"]
for i in range(5):
th = threading.Thread(target=tom, args=(number[i],))
# th.setName('mythread')
# print th.getName()
th.start()

说明:Thread()函数有2个参数,一个是target,内容为子线程要执行的函数名称;另一个是args,内容为需要传递的参数。Args 参数看起来有些奇怪,那是因为我们需要传递一个序列给tom函数,但它只接受一个变量,所以我们把逗号放在尾部来创建只有一个参数的序列。创建完子线程,将会返回一个对象,调用对象的start方法,可以启动子线程。

当你运行以上这段代码,会得到以下输出:

Thread-1
zero
Thread-2
one
Thread-3
two
Thread-4
three
Thread-5
four

线程对象的方法:

  • Start() 开始线程的执行

  • Run() 定义线程的功能的函数

  • Join(timeout=None) 程序挂起,直到线程结束;如果给了timeout,则最多阻塞timeout秒

  • getName() 返回线程的名字

  • setName() 设置线程的名字

  • isAlive() 布尔标志,表示这个线程是否还在运行

  • isDaemon() 返回线程的daemon标志

  • setDaemon(daemonic) 把线程的daemon标志设为daemonic(一定要在start()函数前调用)

  • t.setDaemon(True) 把父线程设置为守护线程,当父进程结束时,子进程也结束

2. 继承threading类

import  threading

class mythread(threading.Thread):
def __init__(self,number):
threading.Thread.__init__(self)
self.number = number def run(self):
print threading.current_thread().getName()
print self.number if __name__ == "__main__":
for i in range(5):
th = mythread(i)
th.start()

当你运行以上这段代码,会得到以下输出:

Thread-1
0
Thread-2
1
Thread-3
2
Thread-4
3
Thread-5
4

当然,通常情况下你不会希望输出打印到标准输出。如果不幸真的这么做了,那么最终的显示效果将会非常混乱。你应该使用 Python 的 logging 模块。它是线程安全的,并且表现出色。让我们用 logging 模块修改上面的例子并且给我们的线程命名。代码如下:

import threading
import logging def get_logger():
#创建一个被设置为调试级别的日志记录器
logger = logging.getLogger("mylogger")
logger.setLevel(logging.DEBUG) #设置每行日志的格式。格式包括时间戳、线程名、日志记录级别以及日志信息
fh = logging.FileHandler("threading.log")
fmt = '%(asctime)s - %(threadName)s - %(levelname)s - %(message)s'
formatter = logging.Formatter(fmt)
fh.setFormatter(formatter) logger.addHandler(fh)
return logger def tom(number, logger):
logger.debug(number) if __name__ == "__main__":
logger = get_logger()
number = ["zero", "one", "two", "three", "four"]
sex = ["man", "woman"]
for i in range(5):
th = threading.Thread(target=tom, args=(number[i],logger))
# th.setName('mythread')
# print th.getName()
th.start()

通过继承的方法:

import  threading
import logging class mythread(threading.Thread):
def __init__(self,number,logger):
threading.Thread.__init__(self)
self.number = number
self.logger = logger def run(self):
self.logger.debug("calling-thread")
tom(self.number, self.logger) def get_logger():
logger = logging.getLogger("mylogger")
logger.setLevel(logging.DEBUG) fh = logging.FileHandler("threading.log")
fmt = '%(asctime)s - %(threadName)s - %(levelname)s - %(message)s'
formatter = logging.Formatter(fmt)
fh.setFormatter(formatter) logger.addHandler(fh)
return logger def tom(number, logger): if __name__ == "__main__":
logger = get_logger()
for i in range(5):
th = mythread(i, logger)
th.start()

在 tom 函数中,我们把 print 语句换成 logging 语句。你会注发现,在创建线程时,我们给 doubler 函数传入了 logger 对象。这样做的原因是,如果在每个线程中实例化 logging 对象,那么将会产生多个 logging 单例(singleton),并且日志中将会有很多重复的内容

线程锁与线程同步

由于物理上得限制,各CPU厂商在核心频率上的比赛已经被多核所取代。为了更有效的利用多核处理器的性能,就出现了多线程的编程方式,而随之带来的就是线程间数据一致性和状态同步的困难。解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁。锁由 Python 的 threading 模块提供,并且它最多被一个线程所持有。当一个线程试图获取一个已经锁在资源上的锁时,该线程通常会暂停运行,直到这个锁被释放。

有两种方式为线程加锁:

  1. try...finally

  2. with

代码如下:

import  threading
import logging lock = threading.Lock()
class mythread(threading.Thread):
def __init__(self,number,logger):
threading.Thread.__init__(self)
self.number = number
self.logger = logger def run(self):
lock.acquire()
try:
self.logger.debug("calling-thread")
tom(self.number, self.logger)
finally:
lock.release() def get_logger():
logger = logging.getLogger("mylogger")
logger.setLevel(logging.DEBUG) fh = logging.FileHandler("threading.log")
fmt = '%(asctime)s - %(threadName)s - %(levelname)s - %(message)s'
formatter = logging.Formatter(fmt)
fh.setFormatter(formatter) logger.addHandler(fh)
return logger def tom(number, logger):
with lock:
logger.debug(number) if __name__ == "__main__":
logger = get_logger()
for i in range(5):
with lock:
th = mythread(i, logger)
th.start()

当你真正运行这段代码时,你会发现它只是挂起了。究其原因,是因为我们只告诉 threading 模块获取锁。所以当我们调用第一个函数时,它发现锁已经被获取,随后便把自己挂起了,直到锁被释放,然而这将永远不会发生。

真正的解决办法是使用重入锁(Re-Entrant Lock)。threading 模块提供的解决办法是使用 RLock 函数。即把 lock = threading.lock() 替换为 lock = threading.RLock(),然后重新运行代码,现在代码就可以正常运行了。

线程通信

某些情况下,你会希望线程之间互相通信。就像先前提到的,你可以通过创建 Event 对象达到这个目的。但更常用的方法是使用队列(Queue)。在我们的例子中,这两种方式都会有所涉及。下面让我们看看到底是什么样子的:

import threading

import Queue

def creator(data, q):
"""
生成用于消费的数据,等待消费者完成处理
"""
print('Creating data and putting it on the queue')
for item in data:
evt = threading.Event()
q.put((item, evt)) print('Waiting for data to be doubled')
evt.wait() def my_consumer(q):
"""
消费部分数据,并做处理 这里所做的只是将输入翻一倍 """
while True:
data, evt = q.get()
print('data found to be processed: {}'.format(data))
processed = data * 2
print(processed)
evt.set()
q.task_done() if __name__ == '__main__':
q = Queue()
data = [5, 10, 13, -1]
thread_one = threading.Thread(target=creator, args=(data, q))
thread_two = threading.Thread(target=my_consumer, args=(q,))
thread_one.start()
thread_two.start() q.join()

让我们掰开揉碎分析一下。首先,我们有一个创建者(creator)函数(亦称作生产者(producer)),我们用它来创建想要操作(或者消费)的数据。然后用另外一个函数 my_consumer 来处理刚才创建出来的数据。Creator 函数使用 Queue 的 put 方法向队列中插入数据,消费者将会持续不断的检测有没有更多的数据,当发现有数据时就会处理数据。Queue 对象处理所有的获取锁和释放锁的过程,这些不用我们太关心。

在这个例子中,先创建一个列表,然后创建两个线程,一个用作生产者,一个作为消费者。你会发现,我们给两个线程都传递了 Queue 对象,这两个线程隐藏了关于锁处理的细节。队列实现了数据从第一个线程到第二个线程的传递。当第一个线程把数据放入队列时,同时也传递一个 Event 事件,紧接着挂起自己,等待该事件结束。在消费者侧,也就是第二个线程,则做数据处理工作。当完成数据处理后就会调用 Event 事件的 set 方法,通知第一个线程已经把数据处理完毕了,可以继续生产了。

最后一行代码调用了 Queue 对象的 join 方法,它会告知 Queue 等待所有线程结束。当第一个线程把所有数据都放到队列中,它也就运行结束了。

python多线程创建与使用(转)的更多相关文章

  1. python 多线程,tthread模块比较底层,而threading模块是对thread做了一些包装,multithreading

    Python多线程详解 2016/05/10 · 基础知识 · 1 评论· 多线程 分享到:20 本文作者: 伯乐在线 - 王海波 .未经作者许可,禁止转载!欢迎加入伯乐在线 专栏作者. 1.多线程的 ...

  2. python多线程学习记录

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

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

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

  4. python多线程

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

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

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

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

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

  7. 【python,threading】python多线程

    使用多线程的方式 1.  函数式:使用threading模块threading.Thread(e.g target name parameters) import time,threading def ...

  8. Python多线程和Python的锁

    Python多线程 Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版本中为thread模块,没有下划线)的start_new_thread()函数,另一种基于th ...

  9. 【跟我一起学Python吧】Python 多线程

    其实自我感觉Python的多线程很类似于Java的多线程机制,但是比JAVA的多线程更灵活.在早期的Python多线程实现中,采用了thread模块.例如: from time import ctim ...

随机推荐

  1. JavaScript的DOM操作获取元素周边大小

    一.clientLeft 和 clientTop 这组属性可以获取元素设置了左边框和上边框的大小,目前只提供了 Left 和 Top 这组,并没有提供 Right 和 Bottom. <scri ...

  2. python第六课——判断结构

    1.判断结构 格式三: ① if 条件表达式1: 语句块1 elif 条件表达式2: 语句块2 elif 条件表达式3: 语句块3 elif 条件表达式y: 语句块y else: 语句块z ② 执行流 ...

  3. ios的图片解压

    YYKit SDWebImage FLAnimatedImage YYKit YYCGImageCreateDecodedCopy YYImageCoder 1 2 3 4 5 6 7 8 9 10 ...

  4. HDU4513:完美队形II(Manacher)

    Description Input Output Sample Input   Sample Output   Solution 才发现我之前不会证$Manacher$复杂度……QAQ 题意是求最长向 ...

  5. 【CF1009F】Dominant Indices

    题目 长链剖分板子题啊 长链剖分有几个神奇的性质 所有长链的总点数为\(n\) 任意一个点的\(k\)级祖先所在长链的长度肯定不小于\(k\) 从任意点到根经过的短边数量不超过\(\sqrt{n}\) ...

  6. R语法:<<-为全局变量赋值

    例:在函数内部为全局变量赋值 all_predata_time <- data.frame(pd=0.1,Row=1,preRow=0,pt=0.1,stasid='1',InitDate='1 ...

  7. 拥抱.NET Core系列:MemoryCache 初识 (转载)

    阅读目录 MSCache能做什么? 从IMemoryCache说起 开发者的体验 写在最后 Cache是一个绝大多数项目会用到的一个技术,说起到缓存可能就联想到 Set.Add.Get.Remove. ...

  8. SharePoint中跨列表查询

    1,最近的项目中遇到一个需求,站点中有几十个列表,其中每5,6个列表属于一个模块下的.客户的需求是,首页上显示一个模块下所有列表数据的前5条,并按创建时间排序. 2,刚刚考虑到这块的实现方法时,用的是 ...

  9. 浅谈基于FormsAuthentication的认证

    一般情况下,在我们做访问权限管理的时候,会把用户的正确登录后的基本信息保存在Session中,以后用户每次请求页面或接口数据的时候,拿到 Session中存储的用户基本信息,查看比较他有没有登录和能否 ...

  10. json_decode($str,true)的结果为null

    //$result为传进来的json值 $result = $this->params['auth_result']; //html_entity_decode进行HTML 实体转换为字符 // ...