注:Python代码代码的执行由python虚拟机(也叫解释器主循环)来控制。
Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但任意时候,只有一个程序在CPU中运行。
同样,虽然python解释器可以“运行”多个线程,但在任意时刻,只有一个线程在解释器中运行。
多线程
1、函数式:调用thread模块中的start_new_thread()函数来产生新线程。如:
import time
import thread
def timer(no, interval):
cnt = 0
while cnt<10:
print 'Thread:(%d) Time:%s\n'%(no, time.ctime())
#time.sleep(interval)
cnt += 1
# 线程的结束可以等待线程自然结束,也可以在线程函数中调用 thread.exit() 或 thread.exit_thread() 方法。
thread.exit_thread()
def test():
# 用 thread.start_new_thread() 来创建两个线程
# thread.start_new_thread(function, args[, kwargs]) 的第一个参数是线程函数;第二个参数是传递给线程函数的参数,它必须是tuple类型;kwargs是可选参数
thread1 = thread.start_new_thread(timer, (1,1))
thread2 = thread.start_new(timer, (2,2)) # start_new 是 start_new_thread 的另一个名称, 不过这名称已过时
print '开始运行\n'
time.sleep(1) # 此处如果不睡的话会报错,因为主进程结束而子线程没结束
print '运行结束'
if __name__=='__main__':
test()
2、创建 threading.Thread 的子类来包装一个线程对象,如下例:
import threading
import time
class timer(threading.Thread): #The timer class is derived from the class threading.Thread
def __init__(self, num, interval):
threading.Thread.__init__(self)
self.thread_num = num
self.interval = interval
self.thread_stop = False
def run(self): #Overwrite run() method, put what you want the thread do here
while not self.thread_stop:
print 'Thread Object(%d), Time:%s\n' %(self.thread_num, time.time())
time.sleep(self.interval)
def stop(self):
self.thread_stop = True
def test():
thread1 = timer(1, 1)
thread2 = timer(2, 2)
thread1.start()
thread2.start()
time.sleep(10)
thread1.stop()
thread2.stop()
return
if __name__ == '__main__':
test()
threading.Thread类的使用:
1,在自己的线程类的 __init__ 里调用 threading.Thread.__init__(self, name = threadname) # threadname 为线程的名字
2, run(),通常需要重写,编写代码实现做需要的功能。
3,getName(),获得线程对象名称
4,setName(),设置线程对象名称
5,start(),启动线程
6,jion(timeout=None),等待另一线程结束后再运行。如果给出timeout,则最多阻塞timeout秒
7,setDaemon(bool),设置子线程是否随主线程一起结束,必须在start()之前调用。默认为 False 。
8,isDaemon(),判断线程是否随主线程一起结束。
9,isAlive(),检查线程是否在运行中。
此外threading模块本身也提供了很多方法和其他的类,可以帮助我们更好的使用和管理线程。可以参看http://www.python.org/doc/2.5.2/lib/module-threading.html。
3、使用 threading.Thread 启动线程对象,如下例:
import threading
def worker(a_tid,a_account):
print a_tid,a_account
# 参数 target 是要执行的函数, args 里面的是参数列表,kwargs是字典式的参数列表
th = threading.Thread(target=worker,args=(), kwargs={'a_tid':'a', 'a_account':2} )
# 启动这个线程
th.start()
# 等待线程返回
th.join()
# 或者 threading.Thread.join(th)
# 创建锁
g_mutex = threading.Lock()
# .... code ...
# 使用锁
# 锁定,从下一句代码到释放前互斥访问
g_mutex.acquire()
# .... code ...
# 释放锁
g_mutex.release()
http://www.cnblogs.com/tqsummer/archive/2011/01/25/1944771.html
http://blog.sina.com.cn/s/blog_4b5039210100esc1.html
http://sm4llb0y.blog.163.com/blog/static/18912397200981594357140/
多进程 (从 2.6 起增加了子进程级别的并行开发支持 —— multiprocessing)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os, time
from multiprocessing import current_process, Pool
def test(x):
print current_process().pid, x
#time.sleep(1)
if __name__ == "__main__":
print "main:", os.getpid()
p = Pool(5)
p.map(test, range(13)) # 启动13个子进程
time.sleep(1)
1. Process
我们先从最根本的 Process 入手,看看是如何启动子进程完成并行计算的。上面的 Pool 不过是创建多个 Process,然后将数据(args)提交给多个子进程完成而已。
import os, time
from multiprocessing import current_process, Process
def test(x):
print current_process().pid, x
time.sleep(1)
if __name__ == "__main__":
print "main:", os.getpid()
p = Process(target = test, args = [100])
p.start()
p.join()
程序退出时执行
# 注册 atexit 函数来解决
# 如果中途关闭运行窗口,无法调用结束事件
import threading
import time
import atexit
def clean():
print "clean temp data..."
def test():
for i in range(10):
name = threading.currentThread().name
print name, i
# time.sleep(1)
if __name__ == "__main__":
atexit.register(clean) # 注册程序结束时执行的函数
threading.Thread(target = test).start()
time.sleep(1)
exit(4) # quit() 和 exit() 会等待所有前台线程退出,同时会调用退出函数。
import sys; sys.exit(4) # 和 exit / quit 作用基本相同。等待前台线程退出,调用退出函数。
import os; os._exit(4) # os._exit() 通过系统调用来终止进程的,所有线程和退出函数统统滚蛋。
time.sleep(1)
print "Ho ..."
import subprocess
程序退出时执行
# 通过 subprocess.Popen 函数来解决;但会发生问题,不知道内部是什么原因
import subprocess
proc = subprocess.Popen("python test.py")
proc.wait()
# 前面的程序结束后,才继续执行下面的代码
test_file = open('test.txt', 'wb')
test_file.write('hello') # 这里的写入偶尔会出问题,不知道原因
test_file.close()
控制最大线程数(范例)
'''范例 1, 限制最大线程数量'''
NOTIFY_THREADS = 20 # 最大线程数
urls = get_notify_urls() # 获取要处理的 url 列表(假设这里会返回 tuple|list 类型的数据)
# 采用多线程发请求,可大大提高效率。
threads = []
# 下面用循环控制最大线程数,且保证将 参数 urls 平均分配到各线程,每个线程处理的参数数量大致一样(误差 1 个)
for index in range(NOTIFY_THREADS):
th = threading.Thread(target=send_urls, args=(urls[index::NOTIFY_THREADS],)) # 处理数据的函数名为 send_urls, 接收参数: {list} urls
th.start() # 启动这个线程
threads.append(th)
# 等待各线程返回,避免定时器下次再来重复调用,也为了控制线程数量
for th in threads:
th.join()
'''范例 2, 限制最大线程数量,且根据 uid 分配线程(同一个 uid 须保证在同一个线程内)'''
SEND_PRODUCT_THREAD = 20 # 最大线程数
products = query_products(500) # 获取产品列表(假设这里会返回 tuple<dict> 类型的数据,其中 dict 里面包含 uid 字段)
if not products:
return
# 使用多线程,但需要保证顺序,同一个uid的发货需要保证在同一个线程中
thread_products = {} # 先用一个 dict 来保存各线程需要处理的数据列表,然后逐个遍历这个 dict 来启动多线程
for product_data in products:
uid = product_data['uid']
mo = str(uid % SEND_PRODUCT_THREAD) # 对uid取模
product_list = thread_products.get(mo)
if not product_list:
product_list = []
thread_products[mo] = product_list
product_list.append(product_data)
# 发启各线程处理数据
thread_list = []
for mo, product_list in thread_products.items():
th = threading.Thread(target=send_product, args=(product_list,)) # 处理数据的函数名为 send_product, 接收参数: {list<{dict} product_data>} product_list
th.start() # 启动这个线程
thread_list.append(th) # 保存这个线程
# 等待各线程返回
for th in thread_list:
th.join()
线程锁(线程安全)
import time
import threading
# 线程安全锁
mylock = threading.RLock()
num = 1
def http():
global num
mylock.acquire() # 开启线程安全锁
num += 1
print num
time.sleep(0.1)
print time.time()
mylock.release() # 释放锁
threading_list = []
for i in range(10):
th = threading.Thread(target = http)
th.start()
threading_list.append(th)
for th in threading_list:
th.join()
线程定时器
调用threading提供的定时器。定时器在指定时间之后开始执行,在执行前还可以取消执行。
import threading
import time
def delayed():
print('worker running')
return
t1 = threading.Timer(3, delayed) # 指定 3 秒后运行 delayed 函数
t1.setName('t1')
print(time.localtime())
print('starting timers')
t1.start()
time.sleep(2)
print(time.localtime())
#t1.cancel() # 在执行前可以取消执行
print('done')
# 会在打印 done 之后执行 delayed 函数,打印 'worker running'