进程就是一个运行中的程序,是系统的资源分配和运行调度的一个基本单位。由于cpu的多任务时间片轮转工作机制,所以同一时刻内一个cpu内核只能有一个进程在执行。
linux下创建进程
import os
print os.getpid # 获取当前进程id
pid = os.fork() # 创建一个子进程
# fork 后会产生两次返回值,分别是给父进程和子进程的,如果处于子进程,那么这个返回值永远为0,如果处于主进程,那么这个值就是子进程的pid
# 可以理解为分家后,给了原来家庭的户口本,又给了新家庭的户口本
if pid == 0:
# gitppid 获取父进程pid
print "当前处于子进程:%s,父进程:%s" % (os.getpid(),os.getppid())
else:
print "当前处于父进程:%s,子进程:%s" % (os.getpid(), pid)
windows下创建进程
from multiprocessing import Process
import os
def child_process(name):
print "我是子进程%s:%s" % (name,os.getpid())
if __name__=='__main__':
print ('父进程 %d' % os.getpid())
p = Process(target=run_proc,args=('test',))
p.start()
# join()方法使等待子进程结束后再往下运行,可以用于进程间的同步
p.join()
# p.is_alive() 判断进程实例是否还在执行
# p.terminate()不管任务是否完成,立即终止
进程池
from multiprocessing import Pool
import os,time,random
def worker(msg):
print "执行%s,进程号:%s" % (msg, os.getpid())
pool = Pool(5) # 定义一个进程池,最大进程5
for i in range(0,10):
# apply_async 阻塞方式运行
pool.apply_async(worker,(i,))
# apply 非阻塞方式运行
pool.apply(worker,(i,))
pool.close()
pool.join()
进程通信
from multiprocessing import Process,Queue
def q_write(q,data):
for v in data:
q.put(v)
def q_read(q):
while True:
if not q.empty():
value = q.get(True)
print "read data: %s"%value
else:
break
if __name__='__main_':
q = Queue()
# 如果是进程池使用
#from multiprocessing import Manager
#q = Manager().Queue()
qw = Process(target=q_write,args=(q,['a','b','c']))
qr = Process(target=q_read,args=(q,))
qw.start()
qw.join()
qr=start()
qr=join()
在多进程中,每个进程中所有数据(包括全局变量)都各自拥有一份,互不影响。
线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,与其他线程共享进程所拥有的全部资源。一个进程至少包含一个线程
创建线程
import threading
def run():
print 'thread %s running' % threading.current_thread().name
t = threading.Thread(target=loop,name='LoopThread')
t.start()
t.join()
由于进程中数据在线程之间是共享的,所以多个线程可能会同时对数据文件进行读取修改,这样一来就无法保证了数据的安全性,所以对数据操作时还需要引入锁的概念
# 无锁版
import threading
test_num = 10
def change(num):
global test_num
test_num = test_num + num
test_num = test_num - num
def change_time(n):
for i in range(10000):
change(n)
t1 = threading.Thread(target=change_time,args=(2,))
t2 = threading.Thread(target=change_time,args=(3,))
t1.start()
t2.start()
t1.join()
t2.join()
print test_num
# 有锁版
import threading
lock = threading.Lock()
test_num = 10
def change(num):
global test_num
test_num = test_num + num
test_num = test_num - num
def change_time(n):
for i in range(10000):
# 加锁
lock.acquire()
try:
change(n)
finally:
# 释放锁
lock.release()
t1 = threading.Thread(target=change_time,args=(2,))
t2 = threading.Thread(target=change_time,args=(3,))
t1.start()
t2.start()
t1.join()
t2.join()
print test_num
线程的局部变量
1.设置一个全局字典变量,以线程作为key,线程的私有变量作为value
2.使用 threading.local() 创建全局 ThreadLocal 对象,然后将现成的私有变量绑定到该对象上。
协程本质上是一个单线程,协程间可以中断去执行另外一个程序,执行完后再返回。
由于处在一个线程内,所以不存在读写冲突,控制共享资源不用加锁,更不需用进行线程切换。
在python,yield其实使用的就是协程思想,但yield对协程的支持并不完善。
第三方库gevent则提供了比较完善的支持。
from gevent import monkey
# 修改python自带的一些标准库
monkey.patch_socket()
def f(n):
for i in range(n):
print gevent.getcurrent(), i
# gevent.sleep(0) 交出控制权
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
# 3个greenlet依次运行