进程 && 线程
进程:是内存中的一个独立的句柄,我们可以理解为一个应用程序在内存中就是一个进程。 各个进程之间是内存相互独立,不可共享的
线程:每个应用运行之后就会对应启动一个主线程,通过主线程可以创建多个字线程,各个线程共享主进程的内存空间。
关于线程、进程的解释有一篇有趣而生动的解释(http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html)

GIL(全局解释器锁)
我们知道多进程(mutilprocess) 和 多线程(threading)的目的是用来被多颗CPU进行访问, 提高程序的执行效率。 但是在python内部存在一种机制(GIL),在多线程 时同一时刻只允许一个线程来访问CPU。
GIL 并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。
Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把 GIL 归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL。

虽然python支持多线程,但是由于GIL的限制,在实际运行时,程序运行后开启多个线程,但在通过GIL后同时也只能有一个线程被CPU执行。

多线程
1)多线程执行方法

import time
from threading import Thread

def do_thread(num):
print(“this is thread %s” % str(num))
time.sleep(3)

for i in range(5):
t = Thread(target=do_thread, args=(i,))
t.start()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

以上方法就开启了一个5个线程,target用来定义开启线程后要执行的方法,args为参数

线程的其它方法:

1 setName(), getName()
  setName():   给线程设置一个名字
  getName():   获取线程的名称

import time
from threading import Thread

def do_thread(num):
print(“this is thread %s” % str(num))
time.sleep(3)

for i in range(2):
t = Thread(target=do_thread, args=(i,))
t.start()
t.setName(“Mythread_{0}”.format(str(i)))
print(t.getName())

run result:
this is thread 0
Mythread_0
this is thread 1
Mythread_1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2 setDaemon()
setDaemon(True/False): 设置创建的子线程为前台线程或后台线程.设置为True则子线程为后台线程。线程默认为前台线程(不设置此方法)
前台线程: 当子线程创建完成后,主线程和子线程(前台线程)同时运行,如果主线程执行完成,而子线程还未完成则等待子线程执行完成以后整个程序才结束。
后台线程: 当子线程创建完成后,如果子线程还未结束,而主线程运行结束则不管子线程了,程序就结束。
此方法设置必须在 start() 方法前进行设置, 看代码:

import time
from threading import Thread

def do_thread(num):
print(“this is thread %s” % str(num))
time.sleep(3)
print(“OK”, str(num))

for i in range(2):
t = Thread(target=do_thread, args=(i,))
# 不设置此方法默认前台线程,
#t.setDaemon(True)
t.setName(“Mythread_{0}”.format(str(i)))
t.start()
print(t.getName())
run result:
this is thread 0
Mythread_0
this is thread 1
Mythread_1
OK 0
OK 1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
import time
from threading import Threaddef do_thread(num):print("this is thread %s" % str(num))time.sleep(3)# 执行到此时主线程执行完了,程序结束,下面的代码不会执行print("OK", str(num))for i in range(2):t = Thread(target=do_thread, args=(i,))# 设置线程为后台线程t.setDaemon(True)t.setName("Mythread_{0}".format(str(i)))t.start()print(t.getName())
run result:
this is thread 0
Mythread_0
this is thread 1
Mythread_1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

3 join()
join(timeout) : 多线程的 wait(),当主线程执行 子线程.join() 方法后,主线程将等待子线程执行完再接着执行。当加上timeout参数后,如果超过timeout时间不管子线程有没有执行完都将结束等待
看下面两个例子

import time
from threading import Thread

def do_thread(num):
time.sleep(3)
print(“this is thread %s” % str(num))

for i in range(2):
t = Thread(target=do_thread, args=(i,))
t.setName(“Mythread_{0}”.format(str(i)))
t.start()
print(“print in main thread: thread name:”, t.getName())
run result:
print in main thread: thread name: Mythread_0
print in main thread: thread name: Mythread_1
this is thread 0
this is thread 1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上面无join方法时,主线程执行完print,等待子线程函数中的print执行完成,这个程序退出。 下面我们看看加上join方法后的效果

import time
from threading import Thread

def do_thread(num):
time.sleep(3)
print(“this is thread %s” % str(num))

for i in range(2):
t = Thread(target=do_thread, args=(i,))
t.setName(“Mythread_{0}”.format(str(i)))
t.start()
t.join()
print(“print in main thread: thread name:”, t.getName())
run result:
this is thread 0
print in main thread: thread name: Mythread_0
this is thread 1
print in main thread: thread name: Mythread_1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

当程序运行到join后,将等待子程序执行完成,然后才向下执行。这样真个程序就变成一个单线程的顺序执行了。多线程就没什么鸟用了。

join()与setDaemon()都是等待子线程结束,有什么区别呢:
当执行join()后主线程就停了,直到子线程完成后才开始接着主线程执行,整个程序是线性的
setDaemon() 为前台线程时,所有的线程都在同时运行,主线程也在运行。只不过是主线程运行完以后等待所有子线程结束。这个还是一个并行的执行,执行效率肯定要高于join()方法的。

4 线程锁
线程是内存共享的,当多个线程对内存中的同一个公共变量进行操作时,会导致线程争抢的问题,为了解决此问题,可以使用线程锁。

import time
import threading

def do_thread(num):
global public_num
# 加锁
lock.acquire()
public_num -= 1
# 解锁
lock.release()
time.sleep(1)
print(“public_num in thread_%s is %s” % (str(num), str(public_num)))

public_num = 100
threads_list = []
lock = threading.Lock()
for i in range(50):
t = threading.Thread(target=do_thread, args=(i,))
t.setName(“Mythread_{0}”.format(str(i)))
t.start()
threads.append(t)
# 等待所有子线程结束
for t in threads:
t.join()

print("last result of public_num is ", public_num)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

5 event()
线程的事件, 用于主线程控制子线程的执行。它的本质就是定义了一个全局的flag标识,并通过一些方法来获取、设置此标识。包括:
wait()方法:当flag标识为False时,wait()方法将阻塞,为True时,wait()不阻塞
set()方法:设置flag标识为True
clear()方法: 设置flag标识为False
初始化时flag标识为False(阻塞状态)
is_set()/isSet() : 判断当前flag标识是否为True

import threading

def do(event):

print(<span class="hljs-string">'start'</span>)
<span class="hljs-comment"># 默认初始化状态为False,到这里就阻塞了</span>
event.wait()
print(<span class="hljs-string">'execute\n'</span>)

if name == “main”:
event_obj = threading.Event()
for i in range(10):
t = threading.Thread(target=do, args=(event_obj,))
t.start()

inp = input(<span class="hljs-string">'input:'</span>)
<span class="hljs-keyword">if</span> inp == <span class="hljs-string">'true'</span>:<span class="hljs-comment"># 如果为true,则flag=True,不阻塞,子进程继续运行</span>event_obj.set()
<span class="hljs-keyword">else</span>:event_obj.clear()<div class="hljs-button {2}" data-title="复制" data-report-click="{&quot;spm&quot;:&quot;1001.2101.3001.4259&quot;}"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li></ul></pre>

event一个模拟红绿灯的实例:

def light():linght_time = 0if not event.is_set():event.set()  # Flag = True, 阻塞while True:time.sleep(1)if linght_time < 10:print("Green is on....")elif linght_time < 13:print("Yellow is on ....")elif linght_time < 16:print("Red is on ......")if event.is_set():event.clear()else:    # 大于16, 该重新调绿灯了linght_time = 0event.set()
    linght_time += <span class="hljs-number">1</span>

def car_run(carnum):
while True:
time.sleep(2)
if event.is_set():
print(“car %s is run” % carnum)
else:
print(“CAR %s IS WAITTING…” % carnum)

if name == “main”:
event = threading.Event()
l = threading.Thread(target=light, )
l.start()
for i in range(3):
c = threading.Thread(target=car_run, args=(str(i), ))
c.start()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

6) Semaphore()
Semaphore信号量管理一个内置的计数器:
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

import threading
import time

def do():
semaphro.acquire()
print(“this is {0} set the semaphore”.format(threading.current_thread().getName()))
time.sleep(2)
semaphro.release()
print("\033[1;30mthi is {0} release the semaphore\033[0m".format(threading.current_thread().getName()))

if name == “main”:
semaphro = threading.Semaphore(2)
for i in range(10):
t = threading.Thread(target=do)
t.setName(“Thread_{0}”.format(str(i)))
t.start()
print(“finished”)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

上例中,虽然创建了10个线程,但同时只有2个线程在运行,就是因为在线程中通过Semaphore设置了2个信号量。只有其中一个释放后另其它的线程再能开始执行

python多线程基本操作相关推荐

  1. python 多进程_说说Python多线程与多进程的区别?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  2. python多线程库_python多线程库

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! python 多线程 多线程类似于同时执行多个不同程序,多线程运行有如下优点:使 ...

  3. Python多线程(3)——Queue模块

    Python多线程(3)--Queue模块 Queue模块支持先进先出(FIFO)队列,支持多线程的访问,包括一个主要的类型(Queue)和两个异常类(exception classes). Pyth ...

  4. python统计csv行数_对Python 多线程统计所有csv文件的行数方法详解

    如下所示: #统计某文件夹下的所有csv文件的行数(多线程) import threading import csv import os class MyThreadLine(threading.Th ...

  5. c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划

    作者 | 万里羊责编 | 王晓曼出品 | CSDN博客线程和进程计算机的核心是CPU,它承担了所有的计算任务,就像是一座工厂在时刻运行.如果工厂的资源有限,一次只能供一个车间来使用,也就是说当一个车间 ...

  6. python3 多线程_图解|为什么 Python 多线程无法利用多核

    (给Python开发者加星标,提升Python技能) 来源:后端技术指南针 1.全局解释锁 如题: Python的多线程为什么不能利用多核处理器? 全局解释器锁(Global Interpreter ...

  7. python多线程下的信号处理程序示例

    下面是一个网上转载的实现思路,经过验证,发现是可行的,就记录下来. 思路 python多线程中要响应Ctrl+C的信号以杀死整个进程,需要: 1.把所有子线程设为Daemon: 2.使用isAlive ...

  8. Python 多线程抓取网页 牛人 use raw socket implement http request great

    Python 多线程抓取网页 - 糖拌咸鱼 - 博客园 Python 多线程抓取网页 最近,一直在做网络爬虫相关的东西. 看了一下开源C++写的larbin爬虫,仔细阅读了里面的设计思想和一些关键技术 ...

  9. python 多线程编程之_thread模块

    python 多线程编程之_thread模块 参考书籍:python核心编程 _thread模块除了可以派生线程外,还提供了基本的同步数据结构,又称为锁对象(lock object,也叫原语锁.简单锁 ...

最新文章

  1. Visual Studio Code为什么能这么牛X?
  2. 字符串位加密 php,PHP字符串加密增强版
  3. [C++再学习系列] 前置++与后置++
  4. LSA 安装及管理应用程序
  5. Python语言学习之字符串那些事:python和字符串的使用方法之详细攻略
  6. 完整议程、重磅嘉宾公布,第四范式AI新品发布会持续报名中
  7. ANSYS——对称模型对称边界的确定以及对称边界的约束施加问题
  8. java webservice 身份验证_java-Http基本身份验证不适用于Spring WS和WebS...
  9. Visusl Studio——包含目录、库目录、附加包含目录、附加库目录、附加依赖项之详解
  10. Oracle_spatial的空间操作符介绍
  11. 怎么用ubuntu进入python_ubuntu 下python环境的切换使用
  12. 李彦宏告诫年轻人:向前看两年
  13. Flink 集成 Iceberg 在同程艺龙的生产实践
  14. python 删除文件_lt;python笔记gt;点击工具架,删除filechache的文件
  15. 知识变现 常用课程制作实用工具大全(建议保存)
  16. 小程序简介好看的登录页面(附源码)
  17. 系统架构设计师:软件质量属性
  18. 赛博朋克!灵感来自枫树种子荚的多翼滑翔机,空中可分体
  19. Android学习-手把手教学实现仿微信发带图片朋友圈的UI设计
  20. linux服务器怎么查看cpu配置信息,linux服务器cpu信息查看详解

热门文章

  1. 学术大数据在企业专家对接中的应用
  2. 作者:刘建楠(1963-),男,就职于中国石油庆阳石化公司
  3. 【操作系统】高速缓存和缓冲区
  4. 【Python】处理 TypeError: ‘FirefoxWebElement‘ object is not iterable
  5. 用贪心策略均分纸牌(洛谷P1031题题解,Java语言描述)
  6. 【译】2019年开始使用Typescript
  7. Flutter-Cookbook 非官方翻译
  8. Android开发进阶1 思维改变 如何知道我需要学什么(上)
  9. 带你玩转css3的3D!
  10. 锋利的jQuery第2版学习笔记8~11章