Python——进程、线程、与协程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37049781/article/details/83418924

进程

进程就是一个运行中的程序,是系统的资源分配和运行调度的一个基本单位。由于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依次运行

猜你喜欢

转载自blog.csdn.net/qq_37049781/article/details/83418924