Python学习目录python
对于操做系统来讲,一个任务就是一个进程(Process),好比打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。数据库
有些进程还不止同时干一件事,好比Word,它能够同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就须要同时运行多个“子任务”,咱们把进程内的这些“子任务”称为线程(Thread)。编程
Python的os
模块封装了常见的系统调用,其中包括fork
,能够在Python程序中轻松建立子进程:浏览器
import os
print('Process (%s) start...' % os.getpid())
# Only works on Unix/Linux/Mac:
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))
复制代码
运行结果以下:网络
Process (876) start...
I (876) just created a child process (877).
I am child process (877) and my parent is 876.
复制代码
因为Windows没有fork
调用,上面的代码在Windows上没法运行。因为Mac系统是基于BSD(Unix的一种)内核,因此,在Mac下运行是没有问题的,推荐你们用Mac学Python!多线程
若是你打算编写多进程的服务程序,Unix/Linux无疑是正确的选择。因为Windows没有fork
调用,难道在Windows上没法用Python编写多进程的程序?函数式编程
因为Python是跨平台的,天然也应该提供一个跨平台的多进程支持。multiprocessing
模块就是跨平台版本的多进程模块。函数
multiprocessing
模块提供了一个Process
类来表明一个进程对象,下面的例子演示了启动一个子进程并等待其结束:oop
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')
复制代码
执行结果以下:post
Parent process 928.
Process will start.
Run child process test (929)...
Process end.
复制代码
建立子进程时,只须要传入一个执行函数和函数的参数,建立一个Process
实例,用start()
方法启动,这样建立进程比fork()
还要简单。
join()
方法能够等待子进程结束后再继续往下运行,一般用于进程间的同步。
Python的标准库提供了两个模块:_thread
和threading
,_thread
是低级模块,threading
是高级模块,对_thread
进行了封装。绝大多数状况下,咱们只须要使用threading
这个高级模块。
启动一个线程就是把一个函数传入并建立Thread
实例,而后调用start()
开始执行:
import time, threading
# 新线程执行的代码:
def loop():
print('thread %s is running...' % threading.current_thread().name)
n = 0
while n < 5:
n = n + 1
print('thread %s >>> %s' % (threading.current_thread().name, n))
time.sleep(1)
print('thread %s ended.' % threading.current_thread().name)
print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)
复制代码
执行结果以下:
thread MainThread is running...
thread LoopThread is running...
thread LoopThread >>> 1
thread LoopThread >>> 2
thread LoopThread >>> 3
thread LoopThread >>> 4
thread LoopThread >>> 5
thread LoopThread ended.
thread MainThread ended.
复制代码
多线程和多进程最大的不一样在于,多进程中,同一个变量,各自有一份拷贝存在于每一个进程中,互不影响,而多线程中,全部变量都由全部线程共享,因此,任何一个变量均可以被任何一个线程修改,所以,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。
balance = 0
lock = threading.Lock()
def run_thread(n):
for i in range(100000):
# 先要获取锁:
lock.acquire()
try:
# 放心地改吧:
change_it(n)
finally:
# 改完了必定要释放锁:
lock.release()
复制代码
当多个线程同时执行lock.acquire()
时,只有一个线程能成功地获取锁,而后继续执行代码,其余线程就继续等待直到得到锁为止。
得到锁的线程用完后必定要释放锁,不然那些苦苦等待锁的线程将永远等待下去,成为死线程。因此咱们用try...finally
来确保锁必定会被释放。
import threading
# 建立全局ThreadLocal对象:
local_school = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
复制代码
执行结果:
Hello, Alice (in Thread-A)
Hello, Bob (in Thread-B)
复制代码
全局变量local_school
就是一个ThreadLocal
对象,每一个Thread
对它均可以读写student
属性,但互不影响。你能够把local_school
当作全局变量,但每一个属性如local_school.student
都是线程的局部变量,能够任意读写而互不干扰,也不用管理锁的问题,ThreadLocal
内部会处理。
能够理解为全局变量local_school
是一个dict
,不但能够用local_school.student
,还能够绑定其余变量,如local_school.teacher
等等。
ThreadLocal
最经常使用的地方就是为每一个线程绑定一个数据库链接,HTTP请求,用户身份信息等,这样一个线程的全部调用到的处理函数均可以很是方便地访问这些资源。