博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python线程进程笔记
阅读量:4027 次
发布时间:2019-05-24

本文共 6144 字,大约阅读时间需要 20 分钟。

调度算法
时间片轮流
优先级调度
进程:
1、导入os模块
2、ret=os.fork():创建一个子进程
3、分为两种情况:ret==0:
ret!=0:
例:
import os
   
# 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以,我们不用folk()了解即可
   
pid = os.fork()
print(pid)//在父进程打印的是子进程的id
   
if pid == 0:
     
 
print('--子进程--%d---'%os.getpid())
 
elif pid>0:
       
print('--父进程--%d-%d-'%(os.getpid(),os.getppid()))
else:
print('调用失败')
print("父子进程都执行的代码")
结果:
20570
--父进程--20569--
0
---子进程---20570-20569-
普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,
因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。
子进程永远返回0,而父进程返回子进程的ID。
这样做的理由是,一个父进程可以fork出很多子进程,
所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。
注意:
1、父子进程的先后顺序,父进程不会因为子进程没有结束,而不结束
2、多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响
3、父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法
4、fork函数,只在Unix/Linux/Mac上运行,windows不可以,以后不用fock()
multiprocessing(重点):linux和windows都可以执行
multiprocessing模块提供了一个Process类来代表一个进程对象
例:
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
   
print('子进程运行中,name= %s ,pid=%d...' % (name, os.getpid()))
if __name__=='__main__':
   
print('父进程 %d.' % os.getpid())
   
p = Process(target=run_proc, args=('test',))
   
print('子进程将要执行')
   
p.start()
p.join()
   
print('子进程已结束')
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。
join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。
注意:
1、主进程会等待子进程完成后,在结束进程
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调用对象;
args:表示调用对象的位置参数元组;
kwargs:表示调用对象的关键字参数字典;
name:为当前进程实例的别名;
group:大多数情况下用不到;
Process类常用方法:
is_alive():判断进程实例是否还在执行;
join([timeout]):是否等待进程实例执行结束,或等待多少秒;
start():启动进程实例(创建子进程);
run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;
terminate():不管任务是否完成,立即终止;
Process类常用属性:
name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;
pid:当前进程实例的PID值;
进程池Pool:
from multiprocessing import Pool  #第一步导入Pool方法
import os,time,random
def worker(msg):
   
t_start = time.time()
   
print("%s开始执行,进程号为%d"%(msg,os.getpid()))
   
#random.random()随机生成0~1之间的浮点数
   
time.sleep(random.random()*2) 
   
t_stop = time.time()
   
print(msg,"执行完毕,耗时%0.2f"%(t_stop-t_start))
po=Pool(3) #定义一个进程池,最大进程数3
for i in range(0,10):
   
#Pool.apply_async(要调用的目标,(传递给目标的参数元祖,))
   
#每次循环将会用空闲出来的子进程去调用目标
   
po.apply_async(worker,(i,))  #注意若元组只有一个值时,要加个逗号
print("----start----")
po.close() #关闭进程池,关闭后po不再接收新的请求
po.join() #,必须放在close语句之后,默认主进程完成后结束,但执行该方法后,会等待po中所有子进程执行完成
print("-----end-----")
多个进程创建比较:
一般使用进程池,不使用folk()
进程间通信-Queue:(重点)
可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息列队程序
    Queue.qsize():返回当前队列包含的消息数量;
    Queue.empty():如果队列为空,返回True,反之False ;
    Queue.full():如果队列满了,返回True,反之False;
    Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True,
消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,
如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常;
    Queue.get_nowait():相当Queue.get(False);
    Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;
    Queue.put_nowait(item):相当Queue.put(item, False);
例:
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
    for value in ['A', 'B', 'C']:
        print 'Put %s to queue...' % value
        q.put(value)
        time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
    while True:
        if not q.empty():
            value = q.get(True)
            print 'Get %s from queue.' % value
            time.sleep(random.random())
        else:
            break
if __name__=='__main__':
    # 父进程创建Queue,并传给各个子进程:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 启动子进程pw,写入:
    pw.start()    
    # 等待pw结束:
    pw.join()
    # 启动子进程pr,读取:
    pr.start()
    pr.join()
    # pr进程里是死循环,无法等待其结束,只能强行终止:
    print ''
    print '所有数据都写入并且读完'
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),
即q=Manager.Queue()来创建队列
多线程-threading
1、使用threading模块
from threading import Thread
t=Thread(target=方法)
t.start()#启动线程
2. 主线程会等待所有的子线程结束后才结束
3、查看线程数量:length = len(threading.enumerate())
4、使用threading模块时,往往会定义一个新的子类class,只要继承threading.Thread就可以了,然后重写run方法
5、多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),
   到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。
6、当线程的run()方法结束时该线程完成。
7、在一个进程内的所有线程共享全局变量,能够在不适用其他方式的前提下完成多线程之间的数据共享(这点要比多进程要好)
   缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
8、列表当做实参传递到线程中----------->t2 = Thread(target=work2, args=(g_nums,))
9、在多线程开发中,全局变量是多个线程都共享的数据,而局部变量等是各自线程的,是非共享的
进程与线程区别:
进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位
线程同步:
同步就是协同步调,按预定的先后次序进行运行
使用互斥锁来实现
互斥锁:
当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
理解:
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;
直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。
互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
#创建锁
mutex = threading.Lock()
#锁定
mutex.acquire([blocking])--->blocking为True,则当前线程会堵塞,直到获取到这个锁为止,为False,则当前线程不会堵塞,默认True
返回类型:True/False
#释放
mutex.release()
ThreadLocal
用threading.local()创建一个全局变量
一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。
ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题
例:
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=('dongGe',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('老王',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
执行结果:
Hello, dongGe (in Thread-A)
Hello, 老王 (in Thread-B)
异步(重点)
同步调用就是你 喊 你朋友吃饭 ,你朋友在忙 ,你就一直在那等,等你朋友忙完了 ,你们一起去
异步调用就是你 喊 你朋友吃饭 ,你朋友说知道了 ,待会忙完去找你 ,你就去做别的了。
例:
from multiprocessing import Pool
import time
import os
def test():
    print("---进程池中的进程---pid=%d,ppid=%d--"%(os.getpid(),os.getppid()))
    for i in range(3):
        print("----%d---"%i)
        time.sleep(1)
    return "hahah"
def test2(args):
    print("---callback func--pid=%d"%os.getpid())
    print("---callback func--args=%s"%args)
pool = Pool(3)
pool.apply_async(func=test,callback=test2)
//callback为回调函数,当子进程完成后,系统告诉主进程去做回调函数的事
while True:
sleep(1)
print("----主进程-pid=%d----"%os.getpid())
运行结果:
---进程池中的进程---pid=9401,ppid=9400--
----0---
----1---
----2---
----主进程-pid=9400----
----主进程-pid=9400----
----主进程-pid=9400----
----主进程-pid=9400----  //停一会先做回调函数的事,做完在做自己的事
---callback func--pid=9400
---callback func--args=hahah
----主进程-pid=9400----
----主进程-pid=9400----
...
1、callback为回调函数,当子进程完成后,系统告诉主进程去做回调函数的事
2、子进程返回的值给回调函数
GIL问题:
Python多线程是假的需要依赖GIL
解决方案:
1、关键部分使用c语言或者其他语言写
2、使用多进程代替多线程
Python多进程是真的

转载地址:http://waobi.baihongyu.com/

你可能感兴趣的文章
VS 2005 CRT函数的安全性增强版本
查看>>
SQL 多表联合查询
查看>>
Visual Studio 2010:C++0x新特性
查看>>
drwtsn32.exe和adplus.vbs进行dump文件抓取
查看>>
cppcheck c++静态代码检查
查看>>
CLOSE_WAIT和TIME_WAIT
查看>>
在C++中使用Lua
查看>>
在Dll中调用自身的位图资源
查看>>
IP校验和详解
查看>>
C++中使用Mongo执行count和distinct运算
查看>>
一些socket的编程经验
查看>>
socket编程中select的使用
查看>>
C++获取文件大小常用技巧分享
查看>>
未来5年大机遇:做贩卖多巴胺的超级玩家
查看>>
关于AIS编码解码的两个小问题
查看>>
GitHub 万星推荐:黑客成长技术清单
查看>>
可以在线C++编译的工具站点
查看>>
关于无人驾驶的过去、现在以及未来,看这篇文章就够了!
查看>>
所谓的进步和提升,就是完成认知升级
查看>>
昨夜今晨最大八卦终于坐实——人类首次直接探测到了引力波
查看>>