python3第十天

线程:

一套流水线的运行过程,操作系统是个工厂,里面有有多个车间(进程),线程就是每个车间生产的流水线,每个进程,默认都会有个线程

进程是资源单元,线程是cpu上的调度单位

线程的创建开销小,共享空间

进程直接是竞争关系,线程之间是协作关系

一、线程的模块threading模块

方式一

from threading import Thread

from multiprocessing import Process

def task():

print(‘is running‘)

if __name__ == ‘__main__‘:

t=Thread(target=task,)#线程

# t=Process(target=task,)#进程

t.start()

print(‘主’)

线程的结果:

is running

进程:

is running

进程开销大

线程开销小

方式二

from threading import Thread

from multiprocessing import Process

class MyThread(Thread):

def __init__(self,name):

super().__init__()

self.name=name

def run(self):

print(‘%s is running‘ %self.name)

if __name__ == ‘__main__‘:

t=MyThread(‘egon‘)

# t=Process(target=task,)

t.start()

print(‘主’)

二、pid:

多线程的pid是一样的

多进程 pid不一样

三、多线程共享同一个进程内的资源:

from threading import Thread

from multiprocessing import Process

n=100

def work():

global n

n=0

if __name__ == ‘__main__‘:

# p=Process(target=work,)

# p.start()

# p.join()

# print(‘主‘,n)

t=Thread(target=work,)

t.start()

t.join()

print(‘主‘,n)

线程的n会变,进程不会。

因为线程共享资源,进程不是,而且进程pid不一样。

四、多线程共享同一进程内存地址空间:

from threading import Thread

msg_l=[]

format_l=[]

def talk():

while True:

msg=input(‘>>: ‘).strip()

msg_l.append(msg)

def format():

while True:

if msg_l:

data=msg_l.pop()

format_l.append(data.upper())

def save():

while True:

if format_l:

data=format_l.pop()

with open(‘db.txt‘,‘a‘) as f:

f.write(‘%s\n‘ %data)

if __name__ == ‘__main__‘:

t1=Thread(target=talk)

t2=Thread(target=format)

t3=Thread(target=save)

t1.start()

t2.start()

t3.start()

Threading其他方法:

#current_thread:当前的线程对象

from threading import Thread,activeCount,enumerate,current_thread

import time

def task():

print(‘%s is running‘ %current_thread().getName())

time.sleep(2)

if __name__ == ‘__main__‘:

t=Thread(target=task,)

t.start()

t.join()#等待task运行结束(系统回收完)

print(t.is_alive())#返回线程是否活动

print(t.getName())#返回线程名

print(enumerate())#当前活跃的进程对象

print(‘主‘)

print(activeCount())#活着的线程数

主线程从执行层面上代表了,其所在进程的执行过程。

五、守护线程

无论是进程还是线程,都遵循:守护会等待主运行完毕后被销毁

需要强调的是:运行完毕并非终止运行

from threading import Thread

import time

def task1():

print(‘123‘)

time.sleep(10)

print(‘123done‘)

def task2():

print(‘456‘)

time.sleep(1)

print(‘456done‘)

if __name__ == ‘__main__‘:

t1=Thread(target=task1)

t2=Thread(target=task2)

t1.daemon=True

t1.start()

t2.start()

print(‘主’)

六、GIL

三个需要注意的点:
1.线程抢的是GIL锁,GIL锁相当于执行权限,拿到执行权限后才能拿到互斥锁Lock,其他线程也可以抢到GIL,但如果发现Lock仍然没有被释放则阻塞,即便是拿到执行权限GIL也要立刻交出来

2.join是等待所有,即整体串行,而锁只是锁住修改共享数据的部分,即部分串行,要想保证数据安全的根本原理在于让并发变成串行,join与互斥锁都可以实现,毫无疑问,互斥锁的部分串行效率要更高

线程1抢到GIL锁,拿到执行权限,开始执行,然后加了一把Lock,还没有执行完毕,即线程1还未释放Lock,有可能线程2抢到GIL锁,开始执行,执行过程中发现Lock还没有被线程1释放,于是线程2进入阻塞,被夺走执行权限,有可能线程1拿到GIL,然后正常执行到释放Lock。。。这就导致了串行运行的效果

七、互斥锁

from threading import Thread,Lockimport timen=100def work():    time.sleep(0.05)    global n    mutex.acquire()    temp=n    time.sleep(0.1)    n=temp-1    mutex.release()

if __name__ == ‘__main__‘:    mutex=Lock()    l=[]    start=time.time()    for i in range(100):        t=Thread(target=work)        l.append(t)        t.start()

for t in l:        t.join()    print(‘run time:%s value:%s‘ %(time.time()-start,n))
#多进程:#优点:可以利用多核优势#缺点:开销大

#多线程:#优点:开销小#缺点:不能利用多核优势

# from threading import Thread# from multiprocessing import Process# import time# #计算密集型# def work():#     res=1#     for i in range(100000000):#         res+=i## if __name__ == ‘__main__‘:#     p_l=[]#     start=time.time()#     for i in range(4):#         # p=Process(target=work) #6.7473859786987305#         p=Thread(target=work) #24.466399431228638#         p_l.append(p)#         p.start()#     for p in p_l:#         p.join()##     print(time.time()-start)

from threading import Threadfrom multiprocessing import Processimport time#IO密集型def work():    time.sleep(2)

if __name__ == ‘__main__‘:    p_l=[]    start=time.time()    for i in range(400):        # p=Process(target=work) #12.104692220687866        p=Thread(target=work) #2.038116455078125        p_l.append(p)        p.start()    for p in p_l:        p.join()

print(time.time()-start)

八、死锁与递归锁

所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

死锁现象from threading import Thread,Lock,RLockimport timemutexA=Lock()mutexB=Lock()class Mythread(Thread):    def run(self):        self.f1()        self.f2()

def f1(self):        mutexA.acquire()        print(‘\033[45m%s 抢到A锁\033[0m‘ %self.name)        mutexB.acquire()        print(‘\033[44m%s 抢到B锁\033[0m‘ %self.name)        mutexB.release()        mutexA.release()

def f2(self):        mutexB.acquire()        print(‘\033[44m%s 抢到B锁\033[0m‘ %self.name)        time.sleep(1)        mutexA.acquire()        print(‘\033[45m%s 抢到A锁\033[0m‘ %self.name)        mutexA.release()        mutexB.release()

if __name__ == ‘__main__‘:    for i in range(20):        t=Mythread()        t.start()

递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁

#递归锁from threading import Thread,Lock,RLockimport timemutex=RLock()class Mythread(Thread):    def run(self):        self.f1()        self.f2()

def f1(self):        mutex.acquire()        print(‘\033[45m%s 抢到A锁\033[0m‘ %self.name)        mutex.acquire()        print(‘\033[44m%s 抢到B锁\033[0m‘ %self.name)        mutex.release()        mutex.release()

def f2(self):        mutex.acquire()        print(‘\033[44m%s 抢到B锁\033[0m‘ %self.name)        time.sleep(1)        mutex.acquire()        print(‘\033[45m%s 抢到A锁\033[0m‘ %self.name)        mutex.release()        mutex.release()

if __name__ == ‘__main__‘:    for i in range(20):        t=Mythread()        t.start()

九、信号量

from threading import Thread,current_thread,Semaphoreimport time,random

sm=Semaphore(5)def work():    sm.acquire()    print(‘%s 上厕所‘ %current_thread().getName())    time.sleep(random.randint(1,3))    sm.release()

if __name__ == ‘__main__‘:    for i in range(20):        t=Thread(target=work)        t.start()

十、进程池,线程池

进程池import requests #pip3 install requestsimport os,timefrom multiprocessing import Poolfrom concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutordef get_page(url):    print(‘<%s> get :%s‘ %(os.getpid(),url))    respone = requests.get(url)    if respone.status_code == 200:        return {‘url‘:url,‘text‘:respone.text}

def parse_page(obj):    dic=obj.result()    print(‘<%s> parse :%s‘ %(os.getpid(),dic[‘url‘]))    time.sleep(0.5)    res=‘url:%s size:%s\n‘ %(dic[‘url‘],len(dic[‘text‘])) #模拟解析网页内容    with open(‘db.txt‘,‘a‘) as f:        f.write(res)

if __name__ == ‘__main__‘:

# p=Pool(4)    p=ProcessPoolExecutor()    urls = [        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,    ]

for url in urls:        # p.apply_async(get_page,args=(url,),callback=parse_page)        p.submit(get_page,url).add_done_callback(parse_page)

p.shutdown()    print(‘主进程pid:‘,os.getpid())

线程池import requests #pip3 install requestsimport os,time,threadingfrom multiprocessing import Poolfrom concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutordef get_page(url):    print(‘<%s> get :%s‘ %(threading.current_thread().getName(),url))    respone = requests.get(url)    if respone.status_code == 200:        return {‘url‘:url,‘text‘:respone.text}

def parse_page(obj):    dic=obj.result()    print(‘<%s> parse :%s‘ %(threading.current_thread().getName(),dic[‘url‘]))    time.sleep(0.5)    res=‘url:%s size:%s\n‘ %(dic[‘url‘],len(dic[‘text‘])) #模拟解析网页内容    with open(‘db.txt‘,‘a‘) as f:        f.write(res)

if __name__ == ‘__main__‘:

# p=Pool(4)    p=ThreadPoolExecutor(3)    urls = [        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,        ‘http://www.baidu.com‘,    ]

for url in urls:        # p.apply_async(get_page,args=(url,),callback=parse_page)        p.submit(get_page,url).add_done_callback(parse_page)

p.shutdown()    print(‘主进程pid:‘,os.getpid())
时间: 2024-11-01 10:30:51

python3第十天的相关文章

一 .linux上安装 python git redis nginx

一     Linux平台上  python  git  redis nginx 源码包安装 下载依赖库 yum -y install gcc gcc-c++ autoconf automake yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel yum -y install gcc automake autoconf libtool make 1. Python安装图解 https://www.cnblogs

Python进阶(三十四)-Python3多线程解读

Python进阶(三十四)-Python3多线程解读 线程讲解 ??多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度. 程序的运行速度可能加快. 在一些等待的任务实现上如用户输入.文件读写和网络收发数据等,线程就比较有用了.在这种情况下我们可以释放一些珍贵的资源如内存占用等等. ??线程在执行过程中与进程还是有区别的.每个独立

Python3网络爬虫(十):这个帅哥、肌肉男横行的世界(爬取帅哥图)

"-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> Python3网络爬虫(十):这个帅哥.肌肉男横行的世界(爬取帅哥图) - Jack-Cui - 博客频道 - CSDN.NET Jack-Cui 努力-是为了将运气成分降到最低 目录视图 摘要视图 订阅 [活动]2017 CSDN博客专栏评选 &nbsp [5月书讯

python3 练习题100例 (十八)托儿所问题

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """练习十八:某托儿所有大.中.小三个班级,其儿童月龄分别用如下 三个列表表示: x = [18, 18, 19, 19, 24, 23, 22, 22, 21, 20, 19, 22, 23, 24, 24] y = [25, 28, 30, 29, 28, 27, 27, 25, 26, 25, 26, 27, 24] z = [31, 33, 32, 32, 32, 34,

python3 练习题100例 (十九)

#!/usr/bin/env python3 # -*- coding: utf-8 -*- """练习十九:计算1-2+3...+99中除了88以外所有数的和""" __author__ = 'Fan Lijun' s1 = 0 s2 = 0 for x in range(1, 100, 2): s1 += x for y in range(2, 100, 2): s2 += y print(s1 - s2 + 88) 原文地址:https:/

从零开始学习PYTHON3讲义(十二)画一颗心送给你

(内容需要,本讲使用了大量在线公式,如果因为转帖网站不支持公式无法显示的情况,欢迎访问原始博客.) <从零开始PYTHON3>第十二讲 上一节课我们主要讲解了数值计算和符号计算.数值计算的结果,很常用的目的之一就是用于绘制图像,从图像中寻找公式的更多内在规律. Python科学绘图 科学绘图是计算机图形学的一个重要分支.同其它绘图方式相比,更简单易用,能让使用者把工作的主要精力集注在公式和算法上而不是绘图本身.此外科学绘图的工具包普遍精度更高,数据.图的对应关系准确,从而保证基于图的研究工作顺

Python3快速入门(十)——Python3网络编程

Python3快速入门(十)--Python3网络编程 一.socket模块简介 Python 提供了两个级别访问的网络服务,低级别的网络服务支持基本的 Socket,提供了标准的BSD Sockets API,可以访问底层操作系统Socket接口的全部方法:高级别的网络服务模块 SocketServer, 提供了服务器中心类,可以简化网络服务器的开发.socket不支持多并发,socketserver是对socket的再封装,简化网络服务器版的开发. 二.socket模块接口 1.socket

Python3快速入门(十二)——NumPy

Python3快速入门(十二)--NumPy 一.NumPy简介 1.NumPy简介 NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,同时对数组运算提供了大量的数学函数库.Numpy 是一个运行速度非常快的数学库,内部解除了CPython的GIL(全局解释器锁),运行效率极好,主要用于数组计算,是大量机器学习框架的基础库,NumPy主要包括如下:(1)强大的N维数组对象 ndarray(2)广播功能函数(3)整合 C/C++/

Python3快速入门(十五)——Pandas数据处理

Python3快速入门(十五)--Pandas数据处理 一.函数应用 1.函数应用简介 如果要将自定义函数或其它库函数应用于Pandas对象,有三种使用方式.pipe()将函数用于表格,apply()将函数用于行或列,applymap()将函数用于元素. 2.表格函数应用 可以通过将函数对象和参数作为pipe函数的参数来执行自定义操作,会对整个DataFrame执行操作. # -*- coding=utf-8 -*- import pandas as pd import numpy as np