Python 学习笔记 - 线程(1)

这是第一篇Python多线程的学习笔记,看看什么是多线程,以及如何创建他。

之前Python写的脚本程序里面,我们用到的都是单进程单线程的操作。

例如

传统的单进程,单线程的程序

import time
def f1(arg,):
    time.sleep(5)
    print(arg)
for i in range(10):
    f1(i)

然而很多时候,我们需要并发的同时处理多个任务,举个例子,一个播放软件在放电影的时候,他需要同时播放图形,声音,字幕,这个时候他就创建了一个播放软件的进程,然后其内部又运行了多个线程(第一个线程叫做主线程),其中一个线程放图像,一个放声音,一个字幕等等。从这个例子可以知道,一个进程又可以包括多个线程。

因此呢,如果我们需要实现多个任务处理,我们可以使用:

  1. 多进程
  2. 多线程
  3. 多进程+多线程

在Python里面,他有个特殊的规定,每个进程里面同一时间只能有一个线程让CPU执行;而C#,JAVA里面,任意的线程,即使是同一个进程中的多个线程也是可以同时执行的。因此,Python在处理运算密集型的操作(大量CPU执行)时候,适合使用多进程,因为再多的线程在同一个进程里面也不会同时执行;而IO密集型的操作的时候(比如访问网络,文件操作),因为他不占用CPU的资源,大多时候时间都消耗在IO操作等待上了,因此更适合多线程的处理。

下面来对比看看几个简单的例子。

例1:

几个要点

  1. threading.current_thread()是获取当前线程的实例,主线程的名字就叫做MainThread
  2. t.start()表示启动线程,但是他不一定会立刻执行,因此我们可以看见主线程MainThread完成了之后才执行的这个子线程Thread-1
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
import time
def f1(arg, t=None):
    time.sleep(5)
    print(threading.current_thread().name,arg)

import threading
t = threading.Thread(target=f1, args=(1,))
t.start()# 不代表当前线程会被立即执行
print(threading.current_thread().name)
---------------
MainThread
Thread-1 1

例2:

如果我们在上面的基础上加上一个setDaemon(True)的语句,那么主线程结束之后整个程序就直接结束了,并不会等待子线程的执行

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
import time
def f1(arg, t=None):
    time.sleep(5)
    print(threading.current_thread().name,arg)

import threading
t = threading.Thread(target=f1, args=(1,))
t.setDaemon(True)
t.start()# 不代表当前线程会被立即执行
print(threading.current_thread().name)
---------------
MainThread

例3, 如果我们在例1的基础上使用了t.join(),那么可以指定主线程到了这个地方,就给我等着,可以设置等待的时间,比如t.join(2)就是等待2秒,如果什么都不设置的话,主线程会一直等着直到子线程结束之后才执行

比如

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li
import time
def f1(arg, t=None):
    time.sleep(5)
    print(threading.current_thread().name,arg)

import threading
t = threading.Thread(target=f1, args=(1,))
t.start()# 不代表当前线程会被立即执行
t.join() #主进程在这给我挂起
print(threading.current_thread().name)
---------------
Thread-1 1
MainThread

看了这3个例子,可以发现创建多线程非常的简单,直接导入模块,然后调用模块的Thread()类实例一个对象就是了。如果看看源代码,会发现我们传入的函数和元祖,会在构造函数中封装起来;当我们调用start()方法之后,他会自动调用bootstrap()->bootstrap_inner()->run(),最后在run()里面执行我们自己的函数,并传入参数

    def run(self):
        """Method representing the thread‘s activity.
        You may override this method in a subclass. The standard run() method
        invokes the callable object passed to the object‘s constructor as the
        target argument, if any, with sequential and keyword arguments taken
        from the args and kwargs arguments, respectively.
        """
        try:
            if self._target:
                self._target(*self._args, **self._kwargs)
        finally:
            # Avoid a refcycle if the thread is running a function with
            # an argument that has a member that points to the thread.
            del self._target, self._args, self._kwargs

知道他的工作逻辑之后,下面来看看另外一种创建的方式。我们可以自定义个类来继承Threading.Thread,自己写个构造函数,这样实例化的时候直接从自己封装参数,然后执行super,这样Thread也会执行上面分析的过程,当他执行到run()的时候,因为最下面我们自己定义了一个run()了,那他就不会执行上面的那个而是执行我们自己的。

可以看见,多线程的效果是一样的,但是我们可以添加更多的新功能进去~

Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32
>>> import threading
class MyThread(threading.Thread):
   def __init__(self, func,args):
      self.func = func
      self.args = args
      super(MyThread, self).__init__()
   def run(self):
      self.func(self.args)
def f2(arg):
   print(arg)
obj = MyThread(f2,123)
obj.start()
123
时间: 2024-10-15 16:17:02

Python 学习笔记 - 线程(1)的相关文章

Python 学习笔记 - 线程(2)

前面学习了线程基本的概念和创建线程的两种方法,现在看看多线程如何处理竞争条件(racing condition)的问题. 比如说,下面的例子中 我使用了第二种创建的方式,自定义一个类,继承Thread类,然后自定义run()来执行我的方法.在这个run方法里面,每次都对全局变量加1 在主线程里面,他调用一个自己定义的函数,在这个函数里面创建了5000个线程:每个线程都加入一个列表,然后对每个对象都使用join,这是确保主线程等着直到所有子线程完成.最后输出结果 import time impor

Python 学习笔记 - 线程池

前面我们学校里如何创建多线程,当我们接到一个新的请求时,会创建一个线程,执行完毕之后又销毁掉这个线程.对于一些数目巨大,但是单个快速执行的任务,每个任务真正执行消耗的时间和线程创建销毁的时间可能都差不多.这样一来,线程的效率浪费的比较严重.因此可以考虑使用线程池的技术,预先创建一些空闲的线程,当他们接收具体任务的时候,就去直接执行了,执行完了也不销毁,接着执行下一个任务. Python里面,因为暂时还没有功能完备的线程池,因此这部分功能需要自己实现. 实现的基本原理是创建一个队列,把填充的任务数

python学习笔记——线程threading

1 线程threading 1.1 基本概述 也被称为轻量级的进程. 线程是计算机多任务编程的一种方式,可以使用计算机的多核资源. 线程死应用程序中工作的最小单元 1.2 线程特点 (1)进程的创建开销较大,线程创建开销较小 (2)一个进程中可以包含多个线程 (3)线程依附于进程的存在,多个线程共享进程的资源 (4)每个线程也拥有自己独特的特征,比如ID.指令集 注意: (1)进程有独立的空间,数据安全性较高 (2)线程使用进程的资源,即一般使用全局变量的方式进行线程间通信,所以需要较复杂的同步

OpenCV之Python学习笔记

OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书<OpenCV Computer Vision with Python>,于是就看一遍,顺便把自己掌握的东西整合一下,写成学习笔记了.更需要的朋友参考. 阅读须知: 本文不是纯粹的译文,只是比较贴近原文的笔记:         请设法购买到出版社出版的书,支持正版. 从书名就能看出来本书是介绍在Pytho

Python学习笔记基础篇——总览

Python初识与简介[开篇] Python学习笔记——基础篇[第一周]——变量与赋值.用户交互.条件判断.循环控制.数据类型.文本操作 Python学习笔记——基础篇[第二周]——解释器.字符串.列表.字典.主文件判断.对象 Python学习笔记——基础篇1[第三周]——set集合 Python学习笔记——基础篇2[第三周]——计数器.有序字典.元组.单(双)向队列.深浅拷贝.函数.装饰器 Python学习笔记——基础篇[第四周]——迭代器&生成器.装饰器.递归.算法.正则表达式 Python

python学习笔记三---segmaphore信号量学习

# *-* coding=gb2312 *-* ''' 信号量semaphore 是一个变量,控制着对公共资源或者临界区的访问.信号量维护着一个计数器,指定可同时访问资源或者进入临界区的线程数. 每次有一个线程获得信号量时,计数器-1.若计数器为0,其他线程就停止访问信号量,直到另一个线程释放信号量. ''' import threading import random import time class MyThread(threading.Thread): availableTables=[

Python学习笔记进阶篇——总览

Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(Socket编程进阶&多线程.多进程) Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(异常处理) Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(多线程与进程池) Python学习笔记——进阶篇[第九周]———线程.进程.协程篇(队列Queue和生产者消费者模型) Python学习笔记——进阶篇[第九周]———协程 Python学习笔记——进阶篇[第九周]———MYSQL操作

python &nbsp; 学习笔记 (核心)

python    学习笔记 (核心) Python解释器从头到尾一行接一行执行脚本 # -*- coding: UTF-8 -*-    //字符编码 不区分单引号和双引号,x='hello',x[0],x[-1]指最后一个字符,x[2:4]取子串, '''hello''' #hello三引号会保留文本输入时的换行符制表符等不需要转义,用于多行原样输入保存 'hello'+'world' #字符串拼接,'hello'*2 #字符串重复 help(fun) #帮助,help(module.met

python学习笔记12-模块使用

python学习笔记12-模块使用 模块os,sys 什么是模块? 模块os,sys 模块是Python组织代码的一种基本方式 一个Python脚本可以单独运行,也可以导入到另外一个脚本运行,用import hello语句来导入,不用加入.py 什么是Python的 包? Python的模块可以按照目录组织为包 创建一个包的步骤: 创建一个名字为包名的目录 在改目录下创建一个__init__.py文件 根据需要,在该目录下存放脚本文件或已编译的扩展及子包 import pack.m1,pack.