一、Python中两种创建进程的方式
1、os.fork只适用于Linux/Mac
2、使用multiprocessing模块可以跨平台实现多进程
使用os.fork(),像Linux平台上那样创建多进程。
# multiprocessing.py
import os
print 'Process (%s) start...' % os.getpid()
pid = os.fork()
if pid==0:
print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())
else:
print 'I (%s) just created a child process (%s).' % (os.getpid(), pid)
关于fork需要知道以下几点:fork之后程序相当于分叉了,fork会返回两次,每次的返回值都为int。如果此值为0,表示当前进程为父进程,如果此值不为0表示当前进程为子进程且此值代表子进程的id。
使用multiprocessing
进程之间是不共享数据的,它们不共享内存,所以创建进程比较耗费资源。进程之间通信需要类似管道的机制。
from multiprocessing import Process
import time
x = 100
def f():
while 1:
time.sleep(2)
print(x)#这里会一直输出100
if __name__ == '__main__':#必须在main中才可以创建进程
x=2
p = Process(target=f)
p.start()
time.sleep(7)
x=3
time.sleep(3)
print("over")
print(x)
二、编程上的一些用法
主要是两个模块:multiprocessing和threading
1、获取当前线程名称
multiprocessing.current_process().name
threading.current_thread().name
2、多线程编程时,默认情况下,主线程结束之后,等待全部子线程执行完毕才会退出
import threading
import time
def run():
time.sleep(2)
print('当前线程的名字是: ', threading.current_thread().name)
time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
print('这是主线程:', threading.current_thread().name)
thread_list = []
for i in range(5):
t = threading.Thread(target=run)
thread_list.append(t)
for t in thread_list:
t.start()
print('主线程结束!' , threading.current_thread().name)
print('一共用时:', time.time()-start_time)
3、将子线程设置为deamon类型,则主线程不必等待子线程结束
import threading
import time
def run():
time.sleep(2)
print('当前线程的名字是: ', threading.current_thread().name)
time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
print('这是主线程:', threading.current_thread().name)
thread_list = []
for i in range(5):
t = threading.Thread(target=run)
thread_list.append(t)
for t in thread_list:
t.setDaemon(True)
t.start()
print('主线程结束了!' , threading.current_thread().name)
print('一共用时:', time.time()-start_time)
4、在主线程中,使用子线程.join()
来等待子线程运行结束
join()会将一切权力交给子线程,主线程会阻塞直到子线程结束。
import threading
import time
def run():
time.sleep(2)
print('当前线程的名字是: ', threading.current_thread().name)
time.sleep(2)
if __name__ == '__main__':
start_time = time.time()
print('这是主线程:', threading.current_thread().name)
thread_list = []
for i in range(5):
t = threading.Thread(target=run)
thread_list.append(t)
for t in thread_list:
t.setDaemon(True)
t.start()
for t in thread_list:
t.join()
print('主线程结束了!' , threading.current_thread().name)
print('一共用时:', time.time()-start_time)
三、进程和线程的区别和联系
- 进程是重量级的,需要占用较多资源。线程是轻量级的。
- 一个进程可以包括多个线程,但是一个进程只有一个主线程。操作系统的全部进程组成一棵树,父进程的死亡会导致子进程的终止。
- 同一进程的多个线程之间是共享数据的,不同进程之间数据相互独立(进程之间交流比较困难)。
- 尽量使用线程。
Chrome里面每一个tab页都是一个独立的进程,可以打开任务管理器查看一下。
Tomcat中每一次请求都会开辟一个线程,Java强大的异常机制把错误牢牢地抓住了,不然一个线程一崩整个网站就崩了(因为整个tomcat程序就是一个进程,进程中的子线程崩了其它子线程也要受牵连,整个进程就崩了)。
四、为什么说Python中的线程有点鸡肋
不同线程同时访问资源时,需要使用保护机制,Python中使用GIL(解释器全局锁)。直观上,这是一个加在解释器上的全局(从解释器的角度看)锁。这意味着对于任何Python程序,不管有多少的处理器,任何时候都总是只有一个线程在执行。所以,如果没有IO操作,python中的多线程比单线程效率还低。
在任意时间只有一个Python解释器在解释Python bytecode。
如果你的代码是CPU密集型,多个线程的代码很有可能是线性执行的。所以这种情况下多线程是鸡肋,效率可能还不如单线程因为线程切换白费事。
但是,如果你的代码是IO密集型,多线程可以明显提高效率。例如制作爬虫,绝大多数时间爬虫是在等待socket返回数据。这个时候C代码里是有release GIL的,最终结果是某个线程等待IO的时候其他线程可以继续执行。
参考资料
关于Python多线程、多进程,看完廖雪峰的教程就足够了。
廖雪峰Python教程