【Python】进程和线程
学习廖老师的py官网的笔记
多任务的实现方式有三种方式:
1、多进程
2、多线程
3、多进程+多线程(这种比较复杂,实际很少采用)
【多进程】
1、在mac中创建子进程使用Python封装的fork()系统调用。
import os pid = os.fork()
pid
2、在windows上的实现。
使用multiprocessing模块的Process类。
为了观察,还加了一小段代码~
# -*- coding: utf-8 -*- from multiprocessing import Process
import os # 这里是子进程要执行的代码
def run_proc(name):
print('Run child process %s (pid=%s)...' % (name, os.getpid())) if __name__=='__main__':
print('Parent process %s.' % os.getpid())
greeting = input('hi~')
print(greeting)
p = Process(target=run_proc, args=('MyTest',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')
然后就观察到:
结束:
$python test.py
Parent process 1388.
hi~ hi!
hi!
Child process will start.
Run child process MyTest (pid=12680)...
Child process end.
join用于进程间的同步,子进程结束后继续往下执行。
3、有时候需要创建大量的进程,(比如应对多用户访问)这个时候就需要使用“进程池”。
#-*- coding: utf-8 -*- from multiprocessing import Pool
import os, time, random def long_time_task(name):
print('run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3) # teme.sleep(sec)\random.random生成一个0<=x<1的数
end = time.time()
print('Task %s run %.2f seconds.' % (name, (end - start))) if __name__=='__main__':
print('Parent process %s' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,)) # 初始化子进程:这里的意思应该是将任务分配给进程并添加参数
print('Waiting all process Done!. ..')
p.close() # 关闭进程池:调用之后就不能再添加新进程了
p.join() # 父进程等待:等待所有子进程执行完毕
print('ALL Done.')
Parent process 8936
Waiting all process Done!. ..
run task 0 (5608)...
run task 1 (11904)...
run task 2 (8212)...
run task 3 (7492)...
Task 0 run 0.86 seconds.
run task 4 (5608)...
Task 4 run 0.85 seconds.
Task 1 run 1.81 seconds.
Task 2 run 2.53 seconds.
Task 3 run 2.88 seconds.
ALL Done.
在join之后宏观来说各个进程应该是并发的,但是task4却在task0执行完之后才开始run。
原因是pool中设置了最大运行并行的进程个数。
p = Pool(4) # 这里设置的是可以同时并发的数量
for i in range(8): # 真正添加的进程数量
run一下:
Parent process 7592
Waiting all process Done!. ..
run task 0 (4596)...
run task 1 (12712)...
run task 2 (9460)...
run task 3 (7308)...
Task 0 run 1.20 seconds.
run task 4 (4596)... # 因为已经有 4 个进程在并行了,因此 task 4需要等待一个进程结束才开始运行,后面的task也是同理,结束一个,加入一个。
Task 3 run 1.23 seconds.
run task 5 (7308)...
Task 4 run 1.26 seconds.
run task 6 (4596)...
Task 1 run 2.46 seconds.
run task 7 (12712)...
Task 2 run 2.63 seconds.
Task 5 run 1.63 seconds.
Task 6 run 0.95 seconds.
Task 7 run 1.92 seconds.
ALL Done.
p = Pool() # 不添加参数就默认为电脑的核数
4、子进程。
”很多时候,子进程并不是自身,而是一个外部进程。“这里看不懂。
#-*- coding: utf-8 -*-
import subprocess print('$ nslookup www.python.org')
r = subprocess.call(['nslookup', 'www.python.org'])
print('Exit code:', r)
D:\labs>python test.py
$ nslookup www.python.org
DNS request timed out.
timeout was 2 seconds.
服务器: UnKnown
Address: 218.85.157.99 非权威应答:
DNS request timed out.
timeout was 2 seconds.
名称: python.map.fastly.net
Address: 151.101.72.223
Aliases: www.python.org Exit code: 0
稍微修改一下,改成编译当前文件夹下的一个.cpp文件:
#-*- coding: utf-8 -*-
import subprocess print('$ g++ prog1.cpp -std=c++11')
r = subprocess.call(['g++', 'prog1.cpp', 'prog1.cpp'])
print('Exit code:', r)
效果和直接在命令行下输入命令是一样的。(.bat)
如果子进程还需要输入,则可以通过communicate()
方法输入。
#-*- coding: utf-8 -*-
import subprocess print('subprocess $ python')
p = subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'a = 1997\nprint(a)\n')
print('output:' + output.decode('utf-8'))
print('Exit code:', p.returncode)
D:\labs>python test.py
subprocess $ python
output:1997 Exit code: 0
5、进程间的通信。
#-*- coding: utf-8 -*-
# 进程间的通信,queue实现示例。
from multiprocessing import Process, Queue
import os, time, random # 这段代码由写数据的进程执行
def write(q):
print('Process to write: %s' % os.getpid())
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random()) # 这段代码由读数据的进程执行
def read(q):
print('Process to read: %s' % os.getpid())
while True:
value = q.get(True)
print('Get %s from queue.' % value) if __name__ == '__main__':
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,)) pw.start()
pr.start()
pw.join()
pr.terminate() # pr默认无限循环,这里一旦pw结束就关掉pr
可以把含有read方法的进程看作服务器,把含有write看作客户端程序。。。q当作存放socket的队列。。
$ python test.py
Process to write: 27524
Put A to queue...
Process to read: 25572
Get A from queue.
Put B to queue...
Get B from queue.
Put C to queue...
Get C from queue.
【多线程】
1、Python中的线程模块有_thread和threading。_thread是threading的底层,通常使用threading就可以了。
2、线程的接口和进程的接口差不多。
任何进程默认启动一个线程。这个默认的线程叫做:MainThread
#-*- coding: utf-8 -*- import time, threading print('current_thread is %s' % threading.current_thread().name)
$ python test.py
current_thread is MainThread
MainThread又可以创建新的线程,方式和创建进程类似:
#-*- coding: utf-8 -*- import time, threading def f():
print('current_thread is %s' % threading.current_thread().name) print('current_thread is %s' % threading.current_thread().name)
t = threading.Thread(target=f, name='>_<')
t.start();
t.join();
print('current_thread is %s' % threading.current_thread().name)
$ python test.py
current_thread is MainThread D:\labs>python test.py
current_thread is MainThread
current_thread is >_<
current_thread is MainThread
默认的线程名为Thread-1
,Thread-2
…
3、多线程和多进程的不同在于,多进程中的每一个进程对程序中的变量都有“副本”,各自互不影响。
而多线程中的各个线程却“共享”变量。
尝试一下,线程的情况:
#-*- coding: utf-8 -*- import time, threading def f():
global data # 需要先声明一下
data = data + 5
print(data) data = 30 t = threading.Thread(target=f, name='>_<')
t2 = threading.Thread(target=f, name='( >_ <)')
t.start();
t2.start();
t.join();
t2.join();
最后输出的是40.
4、Lock.
#-*- coding: utf-8 -*- import threading, time lock1 = threading.Lock() # 创建锁 def task1():
lock1.acquire() # 获取锁
try:
for i in range(10):
print('execute task1...')
finally:
lock1.release() # 释放锁 def task2():
lock1.acquire() # 获取锁
try:
for i in range(10):
print('execute task2...')
finally:
lock1.release() # 释放锁 t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task2)
t1.start()
t2.start()
t1.join()
t2.join()
5、GIL锁。
历史遗留问题,可以通过执行多个py程序来跑满多核cpu。(或者)
【ThreadLocal】
参考:http://python.jobbole.com/86150/
有时候使用局部变量不太方便,所以就引入了threadlocal变量。这个变量实质是一个全局的dict,但是却提供储存局部数据的功能。
怎么创建、访问threadlocal储存的局部数据呢?
#-*- coding: utf-8 -*- import threading, time global_data = threading.local() # 创建 # 每个线程都可以通过 global_data.num 获得自己独有的数据,并且每个线程读取到的 global_data 都不同
def show():
print(threading.current_thread().getName(), global_data.num) def thread_cal():
global_data.num = 0
for i in range(1000):
global_data.num += 1
show() threads = []
for i in range(10):
threads.append(threading.Thread(target=thread_cal))
threads[i].start()
for i in range(10):
threads[i].join()
【进程vs线程】
相对而言,多进程稳定,但是消耗资源大,多线程不稳定,但是消耗资源小。
【分布式进程】
# -*- coding: utf-8 -*- import queue from multiprocessing.managers import BaseManager task_queue = queue.Queue()
result_queue = queue.Queue() class QueueManager(BaseManager):
pass def return_task_queue():
return task_queue def return_result_queue():
return result_queue def test():
QueueManager.register('get_task_queue', callable=return_task_queue)
QueueManager.register('get_result_queue', callable=return_result_queue) manager = QueueManager(address=('127.0.0.1', 5000), authkey=b'abc') manager.start() task = manager.get_task_queue()
result = manager.get_result_queue() for i in range(10):
task.put(i) for i in range(10):
print(result.get()) manager.shutdown() if __name__ == '__main__':
test()
自己写的死活运行不出来。。。
【Python】进程和线程的更多相关文章
- python 进程和线程
python中的进程.线程(threading.multiprocessing.Queue.subprocess) Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就 ...
- Python进程、线程、协程
进程和线程的解释 进程(process)和线程(thread)是操作系统的基本概念,计算机的核心是CPU,它承担了所有的计算任务: 单个CPU一次只能运行一个任务,代表单个CPU总是运行一个进程,其他 ...
- python进程、线程、协程(转载)
python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资 ...
- Python进程和线程
引入进程和线程的概念及区别 1.线程的基本概念 概念 线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但 ...
- Python进程、线程、协程详解
进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配.任务的调度. ...
- python——进程、线程、协程
Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env pytho ...
- Python进程与线程
进程与线程:*进程: 进程是系统中程序执行和资源分配的基本单元, 每个进程都有自己的数据段(存储数据).代码段(存储代码).堆栈段(对象和变量). # 全局变量等资源在多个进程中不能 ...
- python进程和线程(六)
协程 协程,又称微线程,纤程.英文名Coroutine.顾名思义,协程是协作式的,也就是非抢占式的程序(线程是抢占式的).协程的关键字是yield,一看到这个就想到了生成器对不对?那就顺便回顾一下生成 ...
- python 进程、线程与协程的区别
进程.线程与协程区别总结 - 1.进程是计算器最小资源分配单位 - 2.线程是CPU调度的最小单位 - 3.进程切换需要的资源很最大,效率很低 - 4.线程切换需要的资源一般,效率一般(当然了在不考虑 ...
- python进阶:Python进程、线程、队列、生产者/消费者模式、协程
一.进程和线程的基本理解 1.进程 程序是由指令和数据组成的,编译为二进制格式后在硬盘存储,程序启动的过程是将二进制数据加载进内存,这个启动了的程序就称作进程(可简单理解为进行中的程序).例如打开一个 ...
随机推荐
- 开启GitHub模式,now!
(原文地址为:http://www.karottc.com/blog/2014/06/15/current-doing/) 最近看到了一篇文章,该文章的作者将自己连续177天在github上commi ...
- vue-cli 打包(npm run build) 出现 ERROR in xx..js from UglifyJs Unexpected token: punc (()
之前打包还没问题,这次就报错了,后来发现原来是少了 .babelrc 文件, 网上找了好多方法都不行,后来看了之前的项目,原来是少了 .babelrc 文件, 只要在根目录下建立这个文件, 文件内容 ...
- 三角矩阵怎么用MathType输入
虽然现在已经是暑假,但还是有很多学霸们在炎炎夏日中努力奋战,连暑假都不放过.也许正在实验室里面做得昏天暗地,也许是正在跟数据努力奋战,也许还在办公室里面一点一点地码着论文.码论文的时候,不时地要敲着复 ...
- android webview css z-index属性无效
在做android的web页面嵌入的时候,当使用css的z-index设置重叠div失败: 查询google说设置 -webkit-transform:translateZ(0) canvas{ -w ...
- python 的时间复杂度
Python内置方法的时间复杂度 本文翻译自Python Wiki 本文基于GPL v2协议,转载请保留此协议. 本页面涵盖了Python中若干方法的时间复杂度(或者叫“大欧”,“Big O”).该时 ...
- hdu4328(经典dp用悬线法求最大子矩形)
http://wenku.baidu.com/view/728cd5126edb6f1aff001fbb.html 关于悬线法,这里面有详解. 我当时只想到了记录最大长度,却没有想到如果连最左边和最右 ...
- [转]python-元类
转载于:刘羽冲 两句话掌握python最难知识点——元类 千万不要被所谓“元类是99%的python程序员不会用到的特性”这类的说辞吓住.因为每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两 ...
- spring + quartz 定时
springConfig配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=& ...
- ClickHouse RPM packages installation from packagecloud.io
Table of Contents Introduction Script-based installation Install script Install packages after scrip ...
- SQSERVER--函数、开窗函数,-特殊的内容 (for xml path )
1.STUFF SQL Server之深入理解STUFF sql stuff函数用于删除指定长度的字符,并可以在制定的起点处插入另一组字符.sql stuff函数中如果开始位置或长度值是负数,或者如果 ...