python笔记9 线程进程

线程与进程

进程

进程就是一个程序在一个数据集上的一次动态执行过程。进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。

线程

线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能。

进程和线程的关系:

(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。
(3)CPU分给线程,即真正在CPU上运行的是线程。

串行 并行 并发

多年前单核cpu同时执行两个程序就是并发执行.

同步异步

在计算机领域,同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。举个例子,打电话时就是同步通信,发短息时就是异步通信。

 

threading模块

普通执行脚本时 是串行 

import time

def coun(n):
    print('running on number: %s' % n)
    time.sleep(n)

start = time.time()
coun(3)
coun(2)
print('用时:%s秒' % (time.time() - start))     #串行,从上到下依次执行,执行完共耗时5秒

running on number: 3
running on number: 2
用时:5.0006632804870605秒

多线程

import time
import threading           #开多线程的模块

def coun(n):
    print('running on number: %s' % n)
    time.sleep(n)


start = time.time()
t1 = threading.Thread(target=coun,args=(3,))    #此处 开第一个子线程实传入参数3     此处还是主线程执行的
t2 = threading.Thread(target=coun,args=(2,))    #此处 开第二个子线程实传入参数2     此处也是主线程执行的
t1.start()                                      #到此处执行子线程1
t2.start()                               #到此处执行子线程2
print('用时:%s秒' % (time.time() - start))      #整个代码除了 t1.start() t2.start()是子线程执行的其他都是主线程执行的


running on number: 3
running on number: 2
用时:0.000995635986328125秒                   #主线程并没有 执行函数,因此主线程耗时0.0秒   函数由子线程执行

当启动子线程时,子线程和主线程 并发着一起执行

join()

在子线程运行完之前,这个子线程的主线程一直被阻塞,等子线程运行完在继续运行主线程

import time
import threading     #开多线程的模块

def coun(n):
    print('running on number: %s' % n)
    time.sleep(n)
    print('执行结束')


start = time.time()
t1 = threading.Thread(target=coun,args=(3,)) #此处 开第一个子线程实传入参数3
t2 = threading.Thread(target=coun,args=(2,)) #此处 开第二个子线程实传入参数3
t1.start()                     #到此处执行子线程1
t2.start()                     #到此处执行子线程2
t1.join()             #在t1运行完之前,主线程一直被阻塞       
t2.join()             #在t2运行完之前,主线程一直被阻塞
print('用时:%s秒' % (time.time() - start))    #只有在t1和t2共同 运行完之后才继续运行主线程  

running on number: 3
running on number: 2
执行结束
执行结束
用时:3.002174139022827秒   
循环多个子线程并在最慢的运行完成后结束主线程的方法:
import time
import threading     # 开多线程的模块


def c(a):
    print('%s开始' %(a))
    if a == 5:                  #如果是5等待1秒
        time.sleep(1)
        print('%s运行完成'% (a))
    elif a == 1:                 #如果是1等待5秒
        time.sleep(5)
        print('%s运行完成' % (a))
    else:
        time.sleep(a)
        print('%s运行完成' % (a))

threadd_list = []
d = time.time()
for i in range(1, 6):                  #循环开新的子进程   
    t = threading.Thread(target=c,args=(i,))
    threadd_list.append(t)            #将每个子线程的t加入到列表
    t.start()                           #启动子进程
for i in threadd_list:                  
    i.join()                        #循环等待所有子进程结束在继续运行

print('共用时%s' % (time.time() - d))   #共耗时 5秒,最慢的线程5秒
  

1开始
2开始
3开始
4开始
5开始
5运行完成
2运行完成
3运行完成
4运行完成
1运行完成
共用时5.00162410736084

错误方法1:

import time
import threading  # 开多线程的模块


def c(a):
    print('%s开始' %(a))
    if a == 5:                  #如果是5等待1秒
        time.sleep(1)
        print('%s运行完成'% (a))
    elif a == 1:                 #如果是1等待5秒
        time.sleep(5)
        print('%s运行完成' % (a))
    else:
        time.sleep(a)
        print('%s运行完成' % (a))

threadd_list = []
d = time.time()
for i in range(1, 6):                  #循环开新的子进程
    t = threading.Thread(target=c,args=(i,))
    threadd_list.append(t)
    t.start()                           #启动子进程
    t.join()                            #这样在循环里join()会在每次循环时都要等待,结果和串行一样
print('共用时%s' % (time.time() - d))   #共耗时

1开始
1运行完成
2开始
2运行完成
3开始
3运行完成
4开始
4运行完成
5开始
5运行完成
共用时15.006914854049683

错误方法2:

import time
import threading  # 开多线程的模块


def c(a):
    print('%s开始' %(a))
    if a == 5:                  #如果是5等待1秒
        time.sleep(1)
        print('%s运行完成'% (a))
    elif a == 1:                 #如果是1等待5秒
        time.sleep(5)
        print('%s运行完成' % (a))
    else:
        time.sleep(a)
        print('%s运行完成' % (a))

threadd_list = []
d = time.time()
for i in range(1, 6):                  #循环开新的子进程
    t = threading.Thread(target=c,args=(i,))
    threadd_list.append(t)
    t.start()                           #启动子进程
t.join()                #放在循环外,当循环结束时,会执行最后循环的t ,最后的是5对应是1秒
print('共用时%s' % (time.time() - d))   #共耗时

1开始
2开始
3开始
4开始
5开始
5运行完成
共用时1.0022823810577393
2运行完成
3运行完成
4运行完成
1运行完成

setDaemon(True)

将线程声明为守护线程,必须在start()方法之前设置,作用是当主线程运行完成后,不管子线程是否运行完,都随主线程一起退出,与join的作用相反,join是主线程等待子线程结束在继续往下执行

import time
import threading  # 开多线程的模块


def c(a):
    print('%s开始' %(a))
    if a == 5:                  #如果是5等待1秒
        time.sleep(1)
        print('%s运行完成'% (a))
    elif a == 1:                 #如果是1等待5秒
        time.sleep(5)
        print('%s运行完成' % (a))
    else:
        time.sleep(a)
        print('%s运行完成' % (a))

threadd_list = []
d = time.time()
for i in range(1, 6):                  #循环开新的子进程
    t = threading.Thread(target=c,args=(i,))
    threadd_list.append(t)
    t.setDaemon(True)            #主程序结束子程序结束
    t.start()                           #启动子进程

print('共用时%s' % (time.time() - d))   

1开始 2开始 3开始 4开始 5开始 共用时0.0019898414611816406      #主程序共耗时0秒,主程序结束子程序也结束

当有多个子线程而只设置一个守护线程则没有意义,

因为其他子线程并没有运行完,所以主线程并没有真正意义上的运行完,只有所有的子线程都是守护线程才能在主线程运行完直接全部结束,

否则只要有一个子线程在运行都要继续等待.

import time
import threading  # 开多线程的模块


def c(a):
    print('%s开始' %(a))
    if a == 5:                  #如果是5等待1秒
        time.sleep(1)
        print('%s运行完成'% (a))
    elif a == 1:                 #如果是1等待5秒
        time.sleep(5)
        print('%s运行完成' % (a))
    else:
        time.sleep(a)
        print('%s运行完成' % (a))

threadd_list = []
d = time.time()
for i in range(1, 6):                  #循环开新的子进程
    t = threading.Thread(target=c,args=(i,))
    threadd_list.append(t)
    if i == 1:                        #只开启1的守护线程,
        t.setDaemon(True)            
    t.start()                           #启动子进程

print('共用时%s' % (time.time() - d))   #共耗时

1开始
2开始
3开始
4开始
5开始
共用时0.0009970664978027344
5运行完成
2运行完成
3运行完成
4运行完成                         #此处缺少1运行完成,因为当1运行完时之前其他所有子线程都运行结束了,也意味着主线程结束了,因此1与主线程一起结束了

GIL锁

由于GIL锁的存在,python不能并行,只能并发, 因此python不能算是真正意义上的多线程并行运算.,只能是占用一个cpu的一个线程的并发运算

因此,对于密集型运算,python不适用 threading多线程模块

密集型计算串行:

import time
import threading  # 开多线程的模块

def aa():
    a = 1
    for i in range(1,100000):
        a *= i
def bb():
    a = 1
    for i in range(1,100000):
        a *= i
c = time.time()
aa()
bb()
print('耗时%s' %(time.time() - c)) 

耗时5.802525758743286                #密集型并行计算总耗时5.8秒

密集型threading多线程计算 并发:

import time
import threading  # 开多线程的模块

def aa():
    a = 1
    for i in range(1,100000):
        a *= i
def bb():
    a = 1
    for i in range(1,100000):
        a *= i
c = time.time()
t1 = threading.Thread(target=aa)
t2 = threading.Thread(target=bb)
t1.start()
t2.start()
t1.join()
t2.join()
print('耗时%s' %(time.time() - c))
 
耗时6.302755832672119     #密集型threading多线程计算并发  耗时6.3秒 , 计算量越大差距越大 

对于密集型计算的开启multiprocessing多进程会快 ,但是我们不可能无限量开进程

multiprocessing多进程模块

def aa():
    a = 1
    for i in range(1, 100000):
        a *= i


def bb():
    a = 1
    for i in range(1, 100000):
        a *= i
if __name__ == '__main__':    #多进程模块必须这样写if判断,否则报错
    import time
    import multiprocessing  # 引用多进程模块
    c = time.time()
    t1 = multiprocessing.Process(target=aa)   #和多线程用法基本一致
    t2 = multiprocessing.Process(target=bb)
    t1.start()
    t2.start()
    t1.join()                       #也有join和setDaemon()方法
t2.join()
print('耗时%s' %(time.time() - c))
    耗时4.506261587142944 
 
 
 
 
 

 

 

猜你喜欢

转载自www.cnblogs.com/ywrj/p/10282391.html