Python基础-多线程与多进程

摘要:
Import_threadingfromthreadingimportLocknum=0lock=Lock()#应用lockdefrun():globalnumlock。acquire()#锁定num+=1锁定。release()#解锁lis=[]for iinrange:t=线程。螺纹。start()列表。appendfortinlis:tJoin()print7,多进程:Python中的多线程不能使用多核CPU。如果要使用多核CPU,必须使用多个进程。Python中的多进程使用多处理模块。T1.getName()#获取线程名称T1.setName#命名线程T1.setDaemon#设置守护程序线程T1.isDemon()#判断是否为守护程序线程T1.join


一,线程与进程之间的关系:(从知乎上看到的)

一个必须知道的事实:执行一段程序代码,实现一个功能的过程介绍 ,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPS啊什么的必须就位,然后CPU开始执行。这里除了CPU以外所有的就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给他的CPU执行时间用完了,那它就要被切换出去,等待下一次CPU的临幸。在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次他被CPU临幸的运行环境,必须保存。

串联起来的事实:前面讲过在CPU看来所有的任务都是一个一个的轮流执行的,具体的轮流方法就是:先加载程序A的上下文,然后开始执行A,保存程序A的上下文,调入下一个要执行的程序B的程序上下文,然后开始执行B,保存程序B的上下文。。。

========= 重要的东西出现了========
进程和线程就是这样的背景出来的,两个名词不过是对应的CPU时间段的描述,名词就是这样的功能。
  • 进程就是包换上下文切换的程序执行时间总和 = CPU加载上下文+CPU执行+CPU保存上下文

线程是什么呢?
进程的颗粒度太大,每次都要有上下的调入,保存,调出。如果我们把进程比喻为一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成 a,b,c等多个块组合而成。那么这里具体的执行就可能变成:

程序A得到CPU =》CPU加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。

这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境,的更为细小的CPU时间段。

到此全文结束,再一个总结:

进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同,一个进程中包含了多个线程,在一个时间段内,只能有一个线程占用cpu,cpu不能同时执行多个任务,只不过cpu运行速度太快,我们感知不到,就以为,线程可以同时执行,对于多核cpu,实际也同一个时间段也只有一个cpu在工作
 
二,多线程,使用threading模块
一个简单的多线程
 
import threading

import time

def axb(name):
    time.sleep(1)
    print(name)
for i in range(10):
    t=threading.Thread(target=axb,args=(i,))  ##args 定义的是一个元组,必须加逗号,才能识别为元组
    t.start()

print('game over')

三,线程等待

 线程等待,多线程在运行的时候,每个线程都是独立运行的,不受其他的线程干扰,如果想在哪个线程运行完之后,再做其他操作的话,就得等待它完成,那怎么等待呢,使用join,等待线程结束

import threading
import time
def run():
print('qqq')
time.sleep(1)
print('done!')
lis = []
for i in range(5):
t = threading.Thread(target=run)
lis.append(t)
t.start()
for t in lis:
t.join() #主线程等待子线程执行完
print('over')
 

四,获取多线程时执行结果的返回值

例如我们做接口测试时候,需要获取每个线程执行时间

import threading
import time
import requests
run_times = []
#怎么获取到多线程执行的函数里面的返回值
def blog():
    stat_time = time.time()
    r = requests.get('http://www.nnzhp.cn/').text
    end_time = time.time()
    run_time = end_time-stat_time
    run_times.append(run_time)
objs = []
for i in range(100):
    t = threading.Thread(target=blog())
    t.start()
    objs.append(t)
for obj in objs:
    obj.join()#join中可以设置timeout时间,主线程等待时间超过timeout时间后就会继续执行,不再等待
avg = sum(run_times)/len(run_times)
print('平均响应时间是',avg)

五,守护线程:就相当于你是一个国王(非守护线程),然后你有很多仆人(守护线程),这些仆人都是为你服务的,一但你死了,那么你的仆人都给你陪葬。

主线程死掉了(执行完了),那么不管子线程运行完否,都一起结束
import time
import threading

def  test():
    time.sleep(2)
    print('hhhh')
for i in range(5):
    t=threading.Thread(target=test)
    t.setDaemon(True)#设置子线程为守护线程
    t.start()

程序执行结果不会打印 hhhh,因为主线程执行完的时候,子线程还没执行完,所以,主线程死掉了,守护子线程跟着消亡了

六、锁:线程锁就是,很多线程一起在操作一个数据的时候,可能会有问题,就要把这个数据加个锁,同一时间只能有一个线程操作这个数据。

import threading
from threading import Lock

num = 0
lock = Lock()  # 申请一把锁

def run():
    global num
    lock.acquire()  # 加锁
    num += 1
    lock.release()  # 解锁

lis = []
for i in range(5):
    t = threading.Thread(target=run)
    t.start()
    lis.append(t)
for t in lis:
    t.join()
print('over', num)

七,多进程:Python里面的多线程,是不能利用多核CPU的,如果想利用多核CPU的话,就得使用多进程,python中多进程使用multiprocessing模块。

from  multiprocessing  import Process
import time

def test(i):
    time.sleep(1)
    print(i)

if __name__=='__main__':
    for i in range(10):
        p=Process(target=test,args=(i,))
        p.start()

threading与实例对象提供了几个方法可以让我们更直观的学习线程。

threading.active_count()  # 返回当前运行的线程个数
 
threading.enumerate()  # 返回当前运行中的线程list
 
threading.current_thread()  # 返回当前的线程变量
 
t1.start()  # 启动线程
 
t1.is_alive()  # 判断线程是否在运行 运行指启动后、终止前。
 
t1.getName()  # 获取线程名
 
t1.setName('填写更改后的名称')  # 对线程进行命名
 
t1.setDaemon(True)  # 设置守护线程
 
t1.isDaemon()  # 判断是否是守护线程
 
t1.join(timeout=20)  # 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout(可选参数)

免责声明:文章转载自《Python基础-多线程与多进程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇(整理)EF分页的实现Html的label和span的区别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Python中使用正则表达式获取两个字符中间部分

问题背景:当我们爬取网页信息时,对于一些标签的提取是没有意义的,所以需要提取标签中间的信息。 解决办法:用到了re包下的函数 方法1:用到了research()方法和group()方法 方法2:用到了findall()方法 具体实现: import re # 匹配两个字符中间的所有字符 a = '<p>life is short, i use...

python科学计算库-pandas

------------恢复内容开始------------ 1、基本概念 在数据分析工作中,Pandas 的使用频率是很高的,一方面是因为 Pandas 提供的基础数据结构 DataFrame 与 json 的契合度很高,转换起来就很方便。另一方面,如果我们日常的数据清理工作不是很复杂的话,你通常用几句 Pandas 代码就可以对数据进行规整。 Pand...

TensorFlow的初次使用+Python画3D图和计算KL散度

ython计算KL散度import numpy as np import scipy.stats x = [np.random.randint(1,11) for i in range(10)] print(x) print(np.sum(x)) px = x/np.sum(x)#归一化 print(px) y = [np.random.randint...

锁和监视器之间的区别 – Java并发

在面试中你可能遇到过这样的问题:锁(lock)和监视器(monitor)有什么区别? 嗯,要回答这个问题,你必须深入理解Java的多线程底层是如何工作的。 简短的答案是,锁为实现监视器提供必要的支持。详细答案如下。 锁(lock) 逻辑上锁是对象内存堆中头部的一部分数据。JVM中的每个对象都有一个锁(或互斥锁),任何程序都可以使用它来协调对对象的多线程访问...

python 目录与文件的时间操作

在Python中,文件操作主要来自os模块,主要方法如下: os.listdir(dirname):列出dirname下的目录和文件os.getcwd():获得当前工作目录os.curdir:返回当前目录('.')os.chdir(dirname):改变工作目录到dirname os.path.isdir(name):判断name是不是一个目录,name不...

基于无锁的C#并发队列实现

最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer的关于无锁编程一文对此有详细的描述。 无锁编程的目标是在不使用Lock的前提下保证并发过程中共享数据的一致性,其主要的实现基础是CAS操作,也就是compare_and_swap,通过处理器提供的指令,可以原子地更新共享数据,并同时监测其他线程的干...