我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python学习笔记之线程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python学习笔记之线程

1.自定义进程

自定义进程类,继承Process类,重写run方法(重写Process的run方法)。


from multiprocessing import Process
import time
import os
class MyProcess(Process):
    def __init__(self, name):  ##重写,需要__init__,也添加了新的参数。        ##Process.__init__(self) 不可以省略,否则报错:AttributeError:'XXXX'object has no attribute '_colsed'
        Process.__init__(self)
        self.name = name
    def run(self):
        print("子进程(%s-%s)启动" % (self.name, os.getpid()))
        time.sleep(3)
        print("子进程(%s-%s)结束" % (self.name, os.getpid()))
if __name__ == '__main__':
    print("父进程启动")
    p = MyProcess("Ail")
    # 自动调用MyProcess的run()方法
    p.start()
    p.join()
    print("父进程结束")

# 输出结果
父进程启动
子进程(Ail-38512)启动
子进程(Ail-38512)结束
父进程结束

2.进程与线程

多进程适合在CPU密集型操作(CPU操作指令比较多,如科学计算、位数多的浮点计算);

多线程适合在IO密集型操作(读写数据操作比较多的,比如爬虫、文件上传、下载)

线程是并发,进程是并行:进程之间互相独立,是系统分配资源的最小单位,同一个进程中的所有线程共享资源。

进程:一个运行的程序或代码就是一个进程,一个没有运行的代码叫程序。进程是系统进行资源分配的最小单位,进程拥有自己的内存空间,所以,进程间数据不共享,开销大。

进程是程序的一次动态执行过程。每个进程都拥有自己的地址空间、内存、数据栈以及其它用于跟踪执行的辅助数据。操作系统负责其上所有进程的执行,操作系统会为这些进程合理地分配执行时间。

线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程的存在而存在,一个进程至少有一个线程,叫做主线程,多个线程共享内存(数据共享和全局变量),因此提升程序的运行效率。

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一个线程是一个execution context(执行上下文),即一个CPU执行时所需要的一串指令。

主线程:主线程就是创建线程进程中产生的第一个线程,也就是main函数对应的线程。

协程:用户态的轻量级线程,调度由用户控制,拥有自己的寄存器上下文和栈,切换基本没有内核切换的开销,切换灵活。

进程和线程的关系

3.多线程

操作系统通过给不同的线程分配时间片(CPU运行时长)来调度线程,当CPU执行完一个线程的时间片后就会快速切换到下一个线程,时间片很短而且切换速度很快,以至于用户根本察觉不到。多个线程根据分配的时间片轮流被CPU执行,如今绝大多数计算机的CPU都是多核的,多个线程在操作系统的调度下,能够被多个CPU并行执行,程序的执行速度和CPU的利用效率大大提升。绝大对数主流的编程语言都能很好地支持多线程,然而,Python由于GIL锁无法实现真正的多线程。

内存中的线程

4.Thread类方法

(1)start() --开始执行该线程;

(2)run() --定义线程的方法(开发者可以在子类中重写);标准的 run() 方法会对作为 target 参数传递给该对象构造器的可调用对象(如果存在)发起调用,并附带从 args 和 kwargs 参数分别获取的位置和关键字参数。

(3)join(timeout=None) --直至启动的线程终止之前一直挂起;除非给出了timeout(单位秒),否则一直被阻塞;因为 join() 总是返回 None ,所以要在 join() 后调用 is_alive() 才能判断是否发生超时 -- 如果线程仍然存活,则 join() 超时。一个线程可以被 join() 很多次。如果尝试加入当前线程会导致死锁, join() 会引起 RuntimeError 异常。如果尝试 join() 一个尚未开始的线程,也会抛出相同的异常。

(4)is_alive() --布尔值,表示这个线程是否还存活;当 run() 方法刚开始直到 run() 方法刚结束,这个方法返回 True 。

(5)threading.current_thread()--返回当前对应调用者的控制线程的 Thread 对象。例如,获取当前线程的名字,可以是current_thread().name

5.多线程与多进程小Case


from threading import Thread
from multiprocessing import Process
import os
def work():
    print('hello,',os.getpid())
if __name__ == '__main__':
    # 在主进程下开启多个线程,每个线程都跟主进程的pid一样
    t1 = Thread(target=work)  # 开启一个线程
    t2 = Thread(target=work)  # 开启两个线程
    t1.start()  ##start()--It must be called at most once per thread object.It arranges for the object's run() method to be                ## invoked in a separate thread of control.This method will raise a RuntimeError if called more than once on the                ## same thread object.
    t2.start()
    print('主线程/主进程pid', os.getpid())
    # 开多个进程,每个进程都有不同的pid
    p1 = Process(target=work)
    p2 = Process(target=work)
    p1.start()
    p2.start()
    print('主线程/主进程pid',os.getpid())

6.Thread 的生命周期

线程的状态包括:创建、就绪、运行、阻塞、结束。

(1)创建对象时,代表 Thread 内部被初始化;

(2) 调用 start() 方法后,thread 会开始进入队列准备运行,在未获得CPU、内存资源前,称为就绪状态;轮询获取资源,进入运行状态;如果遇到sleep,则是进入阻塞状态;

(3) thread 代码正常运行结束或者是遇到异常,线程会终止。

7.自定义线程

(1)定义一个类,继承Thread;

(2)重写__init__ 和 run();

(3)创建线程类对象;

(4)启动线程。


import time
import threading
class MyThread(threading.Thread):
    def __init__(self,num):
        super().__init__() ###或者是Thread.__init__()
        self.num = num
    def run(self):
        print('线程名称:', threading.current_thread().getName(), '参数:', self.num, '开始时间:', time.strftime('%Y-%m-%d %H:%M:%S'))
if __name__ == '__main__':
    print('主线程开始:',time.strftime('%Y-%m-%d %H:%M:%S'))
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('主线程结束:', time.strftime('%Y-%m-%d %H:%M:%S'))

8.线程共享数据与GIL(全局解释器锁)

如果是全局变量,则每个线程是共享的;

GIL锁:可以用篮球比赛的场景来模拟,把篮球场看作是CPU,一场篮球比赛看作是一个线程,如果只有一个篮球场,多场比赛就要排队进行,类似于一个简单的单核多线程的程序;如果由多块篮球场,多场比赛同时进行,就是一个简单的多核多线程的程序。然而,Python有着特别的规定:每场比赛必须要在裁判的监督之下才允许进行,而裁判只有一个。这样不管你有几块篮球场,同一时间只允许有一个场地进行比赛,其它场地都将被闲置,其它比赛都只能等待。

9.GIL 和 Lock

GIL保证同一时间内一个进程可以有多个线程,但只有一个线程在执行;锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据。

类为threading.Lock

它有两个基本方法, acquire() 和 release() 。

当状态为非锁定时, acquire() 将状态改为 锁定 并立即返回。当状态是锁定时, acquire() 将阻塞至其他线程调用 release() 将其改为非锁定状态,然后 acquire() 调用重置其为锁定状态并返回。

release() 只在锁定状态下调用; 它将状态改为非锁定并立即返回。如果尝试释放一个非锁定的锁,则会引发 RuntimeError 异常。

Caese 如下:


from threading import Thread
from threading import Lock
import time
number = 0
def task(lock):
    global number
    lock.acquire() ##持有锁
    for i in range(100000)      number += 1
    lock.release() ##释放锁
if __name__ == '__main__':
    lock=Lock()
    t1 = Thread(target=task,args=(lock,))
    t2 = Thread(target=task,args=(lock,))    t3 = Thread(target=task,args=(lock,))
    t1.start()    t2.start()    t3.start()    t1.join()    t2.join()    t3.join()        print('number:',number)

10.线程的信号量

class threading.Semaphore([values])

values是一个内部计数,values默认是1,如果小于0,则会抛出 ValueError 异常,可以用于控制线程数并发数。

信号量的实现方式:

s=Semaphore(?)

在内部有一个counter计数器,counter的值就是同一时间可以开启线程的个数。每当我们s.acquire()一次,计数器就进行减1处理,每当我们s.release()一次,计数器就会进行加1处理,当计数器为0的时候,其它的线程就处于等待的状态。

程序添加一个计数器功能(信号量),限制一个时间点内的线程数量,防止程序崩溃或其它异常。

Case


import time
import threading
s=threading.Semaphore(5)    #添加一个计数器
def task():
    s.acquire()    #计数器获得锁
    time.sleep(2)    #程序休眠2秒
    print("The task run at ",time.ctime())
    s.release()    #计数器释放锁

for i in range(40):
    t1=threading.Thread(target=task,args=())    #创建线程
    t1.start()    #启动线程

也可以使用with操作,替代acquire ()和release(),上面的代码调整如下:


import time
import threading
s=threading.Semaphore(5)    #添加一个计数器
def task():    with s:   ## 类似打开文件的with操作
    ##s.acquire()    #计数器获得锁
      time.sleep(2)    #程序休眠2秒
      print("The task run at ",time.ctime())
    ##s.release()    #计数器释放锁

for i in range(40):
    t1=threading.Thread(target=task,args=())    #创建线程
    t1.start()    #启动线程

建议使用with。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python学习笔记之线程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python 爬虫学习笔记之单线程爬虫

介绍 本篇文章主要介绍如何爬取麦子学院的课程信息(本爬虫仍是单线程爬虫),在开始介绍之前,先来看看结果示意图怎么样,是不是已经跃跃欲试了?首先让我们打开麦子学院的网址,然后找到麦子学院的全部课程信息,像下面这样这个时候进行翻页,观看网址的变
2022-06-04

Python 爬虫学习笔记之多线程爬虫

XPath 的安装以及使用 1 . XPath 的介绍 刚学过正则表达式,用的正顺手,现在就把正则表达式替换掉,使用 XPath,有人表示这太坑爹了,早知道刚上来就学习 XPath 多省事 啊。其实我个人认为学习一下正则表达式是大有益处的,
2022-06-04

Python学习笔记

Python介绍Python是一种解释型、面向对象的语言。官网:www.python.orgPython环境解释器:www.python.org/downloads运行方式:交互模式。在IDLE中运行。脚本模式。文件的后缀名为.py。
2023-01-30

Python 学习笔记

rs=Person.objects.all()all返回的是QuerySet对象,程序并没有真的在数据库中执行SQL语句查询数据,但支持迭代,使用for循环可以获取数据。print rs.query 会打印出原生sql语句rs=Person
2023-01-31

Python学习笔记三(Python程序

Linux系统自带的python版本通常都比较低,可以在python官方网站(http://www.python.org/download/)下载最新源码包,然后进行升级安装。1.下载python源码包。wget http://www.py
2023-01-31

python学习笔记(九)之语句1

python学习笔记(九)之语句1printpython2中,print是一个语句,python3中它是一个函数。实例1:print "hello,world!"hello,world!print "hello","world!"hello
2023-01-31

python学习笔记--趣学Python

由反弹球和球拍构成的游戏。球会在屏幕上飞过来,玩家要用球拍把它弹回去画布和画弹球引入模块#Tkinter -- Python的标准GUI库,Tk 接口,是python 内置的安装包from tkinter import *import ra
2023-01-31

Python学习笔记(1)

1 def sum_args(*args):2 return sum(args))3 4 def run_with_positional_args(func, *args):5 return func(*args)6
2023-01-31

Python 学习笔记 - SQLAlc

继续上一篇SQLAlchemy的学习之旅。多对多表的创建表Host和表HostUser通过表HostToHostUser关联在一起from sqlalchemy import create_enginefrom sqlalchemy.ext
2023-01-31

python scapy学习笔记

1. ubuntu下安装gnuplot 转自:http://blog.163.com/gz_ricky/blog/static/182049118201362501316961/2.安装PyX sudo pip install pyx==0
2023-01-31

python scrapy学习笔记

scrapy是python最有名的爬虫框架之一,可以很方便的进行web抓取,并且提供了很强的定制型。一、安装scrapy# pip install scrapy二、基本使用1、初始化scrapy项目# scrapy startproject
2023-01-31

python egg学习笔记

原文链接:http://www.worldhello.net/2010/12/08/2178.html经常接触Python的同学可能会注意到,当需要安装第三方python包时,可能会用到easy_install命令。easy_install
2023-01-31

Android学习笔记之Toast

使用统一标准化的Toast Toast.makeText(Context context, CharSequence text, int duration).show(); /* android.widget.Toast context:
2022-06-06

Android学习笔记之Service

一个Service是App的一个组件,没有任何的UI,可以长时间的在后台无限期运行。可以在主线程之外的单独的线程中执行,也可以在应用程序组件(如活动)中进行管理。例如音乐播放器,可以让音乐在后台进行播放。 Service的两种形式 Star
2022-06-06

Python 学习笔记 - Memcac

Memcached是一个分布式内存对象缓存系统,他把数据缓存在内存里面来减少对数据库的访问,从而提高动态网页的访问速度。他的基本结构是key/value(键值对)。下面看看在Python里面如何使用。首先来安装一下服务器端,豆子直接在一个C
2023-01-31

Python学习笔记(matplotli

Python学习笔记--在Python中如何调整颜色和样式  参靠视频:《Python数据可视化分析 matplotlib教程》链接:https://www.bilibili.com/video/av6989413/?p=6所用的库及环境:
2023-01-30

python-memcached学习笔记

介绍:  memcached是免费、开源、高性能、分布式内存对象的缓存系统(键/值字典),旨在通过减轻数据库负载加快动态web应用程序的使用。  数据类型:只用一种字符串类型1:安装sudo apt-get install memcache
2023-01-31

Python学习笔记四(Python

Python os模块提供了一个统一的操作系统接口函数,通过python os模块可以实现对系统本身的命令,文件,目录进行操作,官方参考文档( http://docs.python.org/library/os)。1)os.sep 可以取代
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录