天道酬勤,学无止境

线程池、协程

文章目录

  • 一、回顾多线程
    • 1.实现多线程的两个方法
    • 2.代码举例
  • 二、回顾爬虫
    • 数据解析主要方法
  • 三、线程池
      • 简单理解:
      • 使用线程池提取并储存一网址菜品信息
  • 四、协程
    • 1.time.sleep()的协程转变
      • 爬虫领域的简单协程模板
    • 2.requests.get()的协程转换
      • 爬取小说内容

一、回顾多线程

1.实现多线程的两个方法

①创建线程 t = Thread(target=func)并启动t.start()

②创建一个继承Thread的类

2.代码举例

from threading import Thread
class My(Thread):
    def run(self):
        for a in range(100):
            print(a)
if __name__ == '__main__':
    t1 = My()
    t1.start()
    for a in range(100):
        print('main', a)

二、回顾爬虫

数据解析主要方法

①re解析:

 主要通过正则表达式来解析提取数据

 举例:

obj1 = re.compile(r"2021必看热片.*?<ul>(?P<ul>.*?)</ul>", re.S)

②bs4解析

主要步骤:

1.把页面源代码交给BeautifulSoup进行处理,生成bs对象

page = BeautifulSoup(resp.text, 'html.parser')  # 指定html解析器``

2.从bs对象中查找数据:find(标签,属性=值), find_all(标签,属性=值)

 page.find("table", class_="hq_table")   
# class是python的关键字,加上_则不为关键字
# table = page.find("table", attrs={"class": "hq_table"})   # 与上一行一致

③path解析

主要内容:

tree = etree.parse("b.html")   # 直接加载html文件
result = tree.xpath("/html/body/ul/li[1]/a/text()")   # /li[1] 表示拿ul下的第一个li标签内容
# xpath索引顺序是从1开始的
result1 = tree.xpath("/html/body/ol/li/a[@href='dapao']/text()")
# a[@href='dapao'] 表示从li标签下找到属性为'dapao'的对应标签   [@XXX=XXX] 是属性的筛选

注:三种解析方式都需要导入对应的包

三、线程池

解释:一次性开辟一些线程,我们用户直接给线程池子提交任务,线程任务的调度交给线程池来完成

使用线程池需要导包:

from concurrent.futures import ThreadPoolExecutor

简单理解:

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
def fun(name):
    for a in range(500):
        print(name,a)

if __name__ == '__main__':
    #创建线程池
    with ThreadPoolExecutor(10) as t: # 分十个线程池
        for i in range(100):
            t.submit(fun,name=f"线程{i}")
    # 等待线程池中任务全部执行完毕,才继续执行(守护)
    print("over")

使用线程池提取并储存一网址菜品信息

步骤:

1.提取单个页面的数据

2.上线程池,多个页面同时抓取

import requests
from lxml import etree
import csv
from concurrent.futures import ThreadPoolExecutor

f= open("data.csv",mode= "w",encoding="utf-8")
cswriter = csv.writer(f)

def download_one_page(url):
    #拿到页面源代码
    resp = requests.get(url)
    html = etree.HTML(resp.text)
    table = html.xpath("/html/body/div[2]/div[4]/div[1]/table")[0]
    # trs = table.xpath("./tr")[1:]  # 从索引为1开始取  或:
    trs = table.xpath("./tr[position()>1]")
    # 拿到每个tr
    for tr in trs:
        txt = tr.xpath("./td/text()")
        # 对数据做简单的处理:\\ / 去掉
        txt = (item.replace("\\","").replace("/","")for item in txt)
        # 把数据存放在文件中
        cswriter.writerow(txt)
    print(url,"提取完毕")

if __name__ == '__main__':
    # for i in range(1,16721):  # 效率地下
    #     download_one_page(f"http://www.xinfadi.com.cn/marketanalysis/0/list/{i}.shtml")

    with ThreadPoolExecutor(50) as t:
        for i in range(200):
            t.submit(download_one_page,url = f"http://www.xinfadi.com.cn/marketanalysis/0/list/{i}.shtml")

    print("全部下载完毕")

在这里插入图片描述

四、协程

import asyncio
async def fun():
    print("4556")
# async关键字使该函数返回值为协程对象
if __name__ == '__main__':
    g=fun()
    #此时的函数是异步协程函数,此函数执行得到的是一个协程对象
    asyncio.run(g) # 运行g协程对象
    # 协程程序运行需要asyncio模块的支持

1.time.sleep()的协程转变

time.sleep()同步的代码–> 异步操作await asyncio.sleep()

import asyncio
import time
async def f1():
    print("101")
    # time.sleep(3)  # 当程序出现同步操作的时候,异步就中断了
    await asyncio.sleep(3)  # 挂起异步操作,使其他过程能够进入线程使用
    print("102")
async def f2():
    print("201")
    await asyncio.sleep(2)
    print("202")
async def f3():
    print("301")
    await asyncio.sleep(4)
    print("302")

if __name__ == '__main__':
    a1=f1()
    a2=f2()
    a3=f3()
    # asyncio.run(a1)
    # asyncio.run(a2)
    # asyncio.run(a3)
    # 以上为分开启动,需要调用并且执行完成才能继续下一个
    tasks = [a1,a2,a3]  # 为使得一次性启动多个任务(协程)
    t1 = time.time()
    asyncio.run(asyncio.wait(tasks))
    t2 = time.time()
    print(t2-t1)
import asyncio
async def f1():
    print("101")
    # time.sleep(3)  # 当程序出现同步操作的时候,异步就中断了
    await asyncio.sleep(3)  # 挂起异步操作,使其他过程能够进入线程使用
    print("102")
async def f2():
    print("201")
    await asyncio.sleep(2)
    print("202")
async def f3():
    print("301")
    await asyncio.sleep(4)
    print("302")
# 创建一个main函数,减轻main方法的使用
async def main():
    # # 第一种
    # a1 = f1()
    # await a1 # 一般await挂起操作放在协程对象前面
    # 第二种
    tasks = [
        asyncio.create_task(f1()),
        asyncio.create_task(f2()),
        asyncio.create_task(f3())
    ]  # py3.8之后需要手动转换,否则asyncio.wait()会警告或报异常
    await asyncio.wait(tasks)
if __name__ == '__main__':
    asyncio.run(main())

爬虫领域的简单协程模板

cio
async def download(url):
    print("开始下载")
    await asyncio.sleep(4)  # 网络请求:requests.get()
    print("下载完成")
async def main():
    urls = [
        "http://www.baidu.com",
        "http://www.bilibili.com"
    ]
    tasks=[]
    for url in urls:
        d = download(url)
        tasks.append(asyncio.create_task(d))
    await asyncio.wait(tasks)
if __name__ == '__main__':
    asyncio.run(main())

注意:一切异步协程都是在单线程的情况下进行的

2.requests.get()的协程转换

requests.get() 同步的代码–> 异步操作aiohttp

举例:使用异步协程爬取三张图片

import asyncio
import aiohttp

urls=[
    "http://kr.shanghai-jiuxin.com/file/2021/0702/662c6fbaa13160d20122c30f97de8bd8.jpg",
    "https://kr.wzh3c.com/file/2020/0608/smalldf980505591cc79141141fc361e98e49.jpg",
    "http://kr.shanghai-jiuxin.com/file/2021/0702/be7e8685eb8808c1c0809227760e5016.jpg"
]
async def aiodownload(url):
    """1.发送请求 2.得到图片内容 3.保存到文件"""
    # s=aiohttp.ClientSession() <==> requests
    #requests.get() <==> s.get()
    name = url.rsplit("/",1)[1]
    async with aiohttp.ClientSession() as s:
        async with s.get(url) as resp:
            # 请求成功,写入文件
            with open(name,mode="wb") as f:
                f.write(await resp.content.read())  # 读取内容是异步的,需要await挂起
    print(name,"ok")

async def main():
    tasks = []
    for url in urls:
        t = aiodownload(url)
        tasks.append(asyncio.create_task(t))
        # tasks.append(asyncio.create_task(aiodownload(url)))

    await asyncio.wait(tasks)

if __name__ == '__main__':
    asyncio.run(main())

所得图片之一:
在这里插入图片描述

爬取小说内容

步骤:

1.同步操作:访问getCatalog 拿到所有章节的cid和名称

2.异步操作:访问getChapterContent 下载所有的文章内容

import json
import requests
import asyncio
import aiohttp
import aiofiles

head={
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"
}
async def aiodownload(cid,b_id,title):
    data = {
        "book_id": b_id,
        "cid": f"{b_id}|{cid}",
        "need_bookinfo": 1
    }
    data = json.dumps(data)
    url = f"http://dushu.baidu.com/api/pc/getChapterContent?data={data}"
    async with aiohttp.ClientSession() as s:
        async with s.get(url,headers=head) as resp:
            dic = await resp.json()
            async with aiofiles.open(title,mode="w",encoding="utf-8") as f:
                await f.write(dic['data']['novel']['content'])
async def getCatalog(url):
    resp = requests.get(url,headers=head)
    dic = resp.json()
    tasks = []
    for item in dic['data']['novel']['items']:  # item就是对应每一章节的名称和cid
        title = item['title']
        cid = item['cid']
        # print(title,cid)
        # 准备异步任务
        t = aiodownload(cid,b_id,title)
        tasks.append(asyncio.create_task(t))
    await asyncio.wait(tasks)
    resp.close()


if __name__ == '__main__':
    b_id = "4306063500"
    url = 'http://dushu.baidu.com/api/pc/getCatalog?data={"book_id":"'+b_id+'"}'
    asyncio.run(getCatalog(url))

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 【python 面试题 - 协程 】- 吊打面试官的经典面试题整理
    协程 1.什么是协程?常用的协程模块有哪些?协程和线程的区别? 协程是一种用户级的轻量型线程,协程是由用户程序自己控制调度,是单线程下的并发,又称微线程,纤程,coroutine 常用模块: greenlet:提供了切换任务的快捷方式,但是遇到io无法自动切换任务,需要手动切换 gevent:开启协程任务并切换的模块,遇到io自动切换任务。 2.协程的join使用来做什么的?它是如何发挥作用的? 阻塞等待调用join方法的协程任务执行完毕,然后继续往后执行。 join产生阻塞,gevent识别到阻塞后,自动切换任务,只要该协程任务没有完成,join会一直产生阻塞,从而使gevent不停的切换到该协程任务上执行。 3.使用协程实现并发的tcp server端 协程实现并发server 4.在一个列表中有多个url,请使用协程访问所有url,将对应的网页内容写入文件保存 协程访问url 1.简述进程、线程、协程的区别以及应用场景? 进程:操作系统资源分配的最小单位,进程之间资源和地址空间独立,进程的创建、销毁、切换开销大,可以利用多核。高密集型计算。 线程:进程中的一条执行过程,操作系统执行的最小单位,共享当前进程的资源,创建、销毁、切换开销比进程小。单存计算模型 协程:基于用户级别控制的,线程中可以自由切换任务,无需操作系统调度,创建比线程更高效。爬虫数据处理。 2.进程池
  • 深入浅出协程、线程和并发问题
      "协程是轻量级的线程",相信大家不止一次听到这种说法。但是您真的理解其中的含义吗?恐怕答案是否定的。接下来的内容会告诉大家协程是如何在 Android 运行时中被运行的,它们和线程之间的关系是什么,以及在使用 Java 编程语言线程模型时所遇到的并发问题。   协程和线程   协程旨在简化异步执行的代码。对于 Android 运行时的协程,lambda 表达式的代码块会在专门的线程中执行。例如,示例中的 斐波那契 运算:   // 在后台线程中运算第十级斐波那契数   someScope.launch(Dispatchers.Default) {   val fibonacci10 = synchronousFibonacci(10)   saveFibonacciInMemory(10, fibonacci10)   }   private fun synchronousFibonacci(n: Long): Long { /* ... */ }   上面 async 协程的代码块,会被分发到由协程库所管理的线程池中执行,实现了同步且阻塞的斐波那契数值运算,并且将结果存入内存,上例中的线程池属于 Dispatchers.Default。该代码块会在未来某些时间在线程池中的某一线程中执行,具体执行时间取决于线程池的策略。   请注意由于上述代码中未包含挂起操作
  • 并发编程(1)——Python 并发编程实战,用多线程、多进程、多协程加速程序运行
    文章目录 1. 视频链接2 有哪些程序提速方法3.python对并发程序的支持4.怎样选择多线程、多进程和多协程?4.1 什么是CPU密集型计算(CPU-bound)、IO密集型计算(IO-bound)?4.2 多线程、多进程、多协程的对比4.3 全局解释器锁GIL4.3.1 python速度慢的两大原因4.3.2 GIL是什么4.3.3 GIL的作用4.3.4 怎样规避GIL带来的限制 5. 多线程5.1 使用多线程,加速爬虫程序5.2 Python线程安全问题5.3 好用的线程池5.3.1 线程池的原理5.3.2 线程池的好处5.3.3 ThreadPoolExecutor的使用语法 6.线程池在web服务中实现加速6.1 web服务的架构以及特点6.2 使用线程池ThreadPoolExecutord加速 7.多进程7.1 多进程multiprocessing的优势7.2 多进程multiprocessing知识梳理(对比多线程threading)7.3 在flask中使用多进程池加速 8.协程8.1 在异步IO中使用信号量控制爬虫并发度 结尾 1. 视频链接 视频链接: Python 并发编程实战,用多线程、多进程、多协程加速程序运行 2 有哪些程序提速方法 多线程并发的基础在于,代码在进行IO数据交互时,系统仍旧可以分配CPU进行计算。 3.python对并发程序的支持
  • go的协程池实现
    Golang 线程 和 协程 的区别 对于进程、线程,都是有内核进行调度,有 CPU 时间片的概念,进行抢占式调度(有多种调度算法) 对于协程(用户级线程),这是对内核透明的,也就是系统并不知道有协程的存在,是完全由用户自己的程序进行调度的,因为是由用户程序自己控制,那么就很难像抢占式调度那样做到强制的 CPU 控制权切换到其他进程/线程,通常只能进行协作式调度,需要协程自己主动把控制权转让出去之后,其他协程才能被执行到。 goroutine 和 协程 区别 本质上,goroutine 就是协程。不同的是,Golang 在 runtime、系统调用等多方面对 goroutine 调度进行了封装和处理,当遇到长时间执行或者进行系统调用时,会主动把当前 goroutine 的CPU § 转让出去,让其他 goroutine 能被调度并执行,也就是 Golang 从语言层面支持了协程。Golang 的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go关键字就可创建一个协程。 内存消耗方面   每个 goroutine (协程) 默认占用内存远比 Java 、C 的线程少。   goroutine:2KB   线程:8MB线程和 goroutine 切换调度开销方面   线程/goroutine 切换开销方面,goroutine 远比线程小   线程:涉及模式切换
  • 进程/线程池、协程、gevent第三方库
    一、进程/线程池 1、进程池 (1)什么是进程池 如果需要创建的子进程数量不大,可以直接利用multiprocess中的Process来创建。但是当需要创建上百个或上千个,手动创建就较为繁琐,这时就可以利用进程池来创建,即current.futures模块中的ProcessPoolExecutor (2)ProcessPoolExecutor的基本方法 1. submit(fn,*args,**kwargs) # 异步提交任务 2. map(func, *iterables, timeout=None, chunksize=1) #取代for循环submit的操作 3. shutdown(wait=True) # 相当于pool.close()+pool.join() wait=True,等待池内所有任务执行完毕回收完资源后才继续 wait=False,立即返回,并不会等待池内的任务执行完毕 但不管wait参数为何值,整个程序都会等到所有任务执行完毕 submit和map必须在shutdown之前 4. result() # 获取结果 5. add_done_callback(fn) # 回调函数,在任务运行完毕后自动触发,传给fn函数一个future,并执行fn函数 (3)进程池的使用 利用列表存放future,从而获取结果 from concurrent.futures
  • golang线程池在IO多路复用中的应用
    前言 之前介绍过基于reactor模式的IO多路复用技术,reactor模式本质上就是循环监听-处理的过程,当处理过程代价很小(比如echo服务器),服务端实际上长期阻塞于监听环节,这样会导致客户端感觉自己的请求是被立即处理的。如果需要服务端支持IO阻塞型应用,单线程的reactor模式就显得不太适合了,因为某个客户端会长期占据IO而使得其余客户端的请求无法及时得到响应。这时候可以对这部分请求单独分配线程池进行处理,以保证轻量的请求不被阻塞。 golang线程池 传统的线程池在golang中可以用更为轻量的协程池代替,具体的做法是分配一定数量的协程,然后利用chan数据结构,将特定的数据通过chan传入到协程池中进行处理。同时设置一个终止的标志,可以选择在一个请求之后、一段时间之后设置这个标志来终止协程,或者保持这个协程池一直处于运行状态来持续处理客户端的请求,我们这里设置在一个请求完成之后就终止当前协程 type Pool struct { req chan interface{} //待处理的请求 done chan bool //完成标志 number int //协程池的大小 } func (p *Pool) Init(num int) { p.req = make(chan interface{}, MaxRequestNum) p.done = make(chan
  • Go Routine并发数量限制
    在这之前,你需要了解什么是进程,线程和协程,对此网上有一大把的概念和解说,很详细,我们仅讲解三者关系,概念性的东西不在累述。 可参考博文进程线程小别 一个程序至少包含一个进程,而一个进程至少包含一个或多个线程,而协程则是更为灵活和轻量级的线程,和线程类似,共享堆,不共享栈,协程的切换一般由程序员在代码中显式控制。它避免了上下文切换的额外耗费,兼顾了多线程的优点,简化了高并发程序的复杂。 协程是一种协作任务控制机制,在最简单的意义上,协程不是并发的,而Goroutine支持并发的。因此Goroutine可以理解为一种Go语言的协程,同时它可以运行在一个或多个线程上。 关于Go routine则是非常简单,只需要在加上关键字 go 即可,那么如何控制go routine的并发量呢?有如下几种方法: 协程池解决 生成协程池,通过协程池控制连接数量,这样每次连接都去协程池里去拿。当然,这个效果并不是很显著,因为Go routine本身就是轻量级、低开销、即创即用的,同时池化技术主要解决的是线程创建和释放过程中的开销和资源占用问题,而这些问题Goroutine本身就已经处理得很好了。如果因为 goroutine 持有资源而要去创建goroutine pool,那只能说明代码的耦合度较高,应该为这类资源创建一个goroutine-safe的对象池,而不是把goroutine本身池化。
  • Python进程池,线程池,协程池
    线程池import threadingimport timedef myThread(): for i in range(10): time.sleep() print('d')sep=threading.Semaphore(1)threadlist=[]for name in ["a","b"]: mythd=threading.Thread(target=myThread,args=(name,)) mythd.start() threadlist.append(myThread)for thread in threadlist: thread.join()进程池import multiprocessingimport timeimport osdef getdata(data): print('start') time.sleep(2) print(os.getpid()) return data**dataif __name__=="__main__": mylist=[x for x in range(100)] pool=multiprocessing.Pool(processes=4) pool_outputs=pool.map(getdata,mylist) pool.close() pool.join() print(pool_outputs)进程池from
  • 进程、线程、协程的区别和联系
    文章目录 (一)进程(二)线程(三)进程和线程直接的区别和联系(四)进程/线程之间的亲缘性(五)进程池与线程池(六)协程 (一)进程 进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。 进程虚拟内存空间 进程状态转换图 虚拟内存空间相关知识见:虚拟内存(Virtual Memory)。 进程间通信(IPC)有以下七种方式: 管道(Pipe,pipe());命名管道(FIFO,open(pipfd, method));消息队列(Message Queue) ;信号量(Semaphore,sigaction()) ;共享内存(Shared Memory);内存映射(Memory Map, mmap());套接字(Socket,socket(AF_INET, SOCK_STREAM, 0))。 IPC相关解析见:linux基础——linux进程间通信(IPC)机制总结。 (二)线程 线程,有时被称为轻量级进程(Lightweight Process,LWP),是操作系统调度(CPU调度)执行的最小单位。 线程状态转换图 进程状态转换图 (三)进程和线程直接的区别和联系 区别: 调º
  • Python高手进阶秘籍:实战的4大并发秘籍
    今天我们就从Python的并发开刀,大家都知道并发有几招,那这几招的性能如何呢,我们一起来实战PK一下! 要点: 手动线程池concurrent.futures线程池concurrent.futures进程池gevent协程 1.实战爬取维基百科例子 平时我们有很多任务,尤其是比较耗时的大量任务要处理,一定会用到并发处理。毕竟串行太慢了,下面我们去爬一个维基百科的网站: 我们来爬取红框里面的导航文本部分,这是一个非常简单的爬虫(关于爬虫的文章前面写的太多太多了,大家可以翻历史文章) 1).连接网页 2).爬取网页 -函数设计的时候我们希望入参是一个元组(url,words),方便后面做并发处理 -网页非常简单,直接用requests取爬取,获取text -用pyquery来解析网页,获取对国家的描述 -数据结构用字典对来存储 2.PK前做点准备工作 1).如果我们现在要爬取100个国家的信息,有几种办法呢: 最慢的串行爬取 自己手动构建一个线程池,把要爬取的100国家都扔到共享队列里面,让多个线程共享爬取 利用concurrent.futures标准库里的线程池来爬去 用多进程来爬取,虽然网页请求是CPU密集型的,用进程有点浪费,但是我们作为对比,是可以试一下的 用协程也叫微线程,是一种绿色线程,用来做高并发很爽 2).为了准确的计算每一种方法的耗时,我们写一个函数专门来计算时间
  • Python多线程、多进程和协程的实例讲解
    线程、进程和协程是什么 线程、进程和协程的详细概念解释和原理剖析不是本文的重点,本文重点讲述在Python中怎样实际使用这三种东西 参考: 进程、线程、协程之概念理解 **进程(Process)**是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。 **协程:**一个程序可以包含多个协程,可以对比于一个进程包含多个线程,因而下面我们来比较协程和线程:我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。 如果你依然在编程的世界里迷茫,可以加入我们的Python学习扣qun:784758214,看看前辈们是如何学习的。从基础的python脚本到web开发、爬虫、django、数据挖掘等,0基础到项目实战的资料都有整理。送给每一位python的小伙伴!每天分享学习方法和趣味实战教程,技术经验!点击加入我们的 python学习者聚集地 准备工作 磨刀不误砍柴工,在用实例讲解线程、进程和协程怎么使用之前,先准备一些工具: 实际上多线程、多进程和协程,都属于并发编程,并发编程的最重要的目标就是提高程序运行的效率
  • Kotlin Coroutine(一):基础及深入
    一、接入 //Kotlin implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.32" //核心库 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3" //Android支持库 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3" //Java8支持库 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.4.3" //lifecycle对于协程的扩展封装 implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" 二、使用方式 常用的两种方式: CoroutineScope.launch()CoroutineScope.async() class
  • 2021-07-03
    线程+爬虫 线程线程的具体实现步骤实例:爬新发地菜价信息 协程理解通过函数调用了解协程的优势实例:爬取三个图片爬100章小说 线程 线程的具体实现步骤 导包: from threading import Thread NO.1 这里我们定义俩方法 def func(): for i in range(1000): print("func",i) def funa(name): for i in range(1000): print(name,i) 线程的实现 if __name__ == '__main__': t1=Thread(target=funa,args=("孙悟空",)) # 传递参数必须是元组所以加逗号 t1.start() t2=Thread(target=funa,args=("牛牛公主",)) t2.start() NO.2 定义类 class MyThread(Thread): def run(self): for i in range(1000): print("func", i) 在主函数里面可以任意造线程实现实例 if __name__ == '__main__': t=MyThread() t1=MyThread() t2=MyThread() t.start() t1.start() t2.start() #....... 线程池:
  • python进阶(17)协程
    协程协程(Coroutine),又称微线程,纤程。(协程是一种用户态的轻量级线程) 作用:在执行 A 函数的时候,可以随时中断,去执行 B 函数,然后中断B函数,继续执行 A 函数 (可以自动切换),但这一过程并不是函数调用(没有调用语句),过程很像多线程,然而协程只有一个线程在执行 通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定 协程和线程差异在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。 协程的标准必须在只有一个单线程里实现并发修改共享数据不需加锁用户程序里自己保存多个控制流的上下文栈一个协程遇到 IO 操作自动切换到其它协程 协程的优点由于自身带有上下文和栈,无需线程上下文切换的开销,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级无需原子操作的锁定及同步的开销方便切换控制流,简化编程模型单线程内就可以实现并发的效果,最大限度地利用 cpu,且可扩展性高,成本低
  • 并发编程之线程和线程池
    1. 线程 线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。 线程是调度CPU资源的最小单位,线程模型分为KLT模型与ULT模型,JVM使用的KLT模型,Java线程与OS线程保持1:1的映射关系,也就是说有一个java线程也会在操作系统里有 一个对应的线程。 线程和进程的主要区别: 进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位 线程的生命状态: New:新建Runnable:运行Blockel:阻塞Waiting:等待Timed_Waiting:超时等待Terminated:终止 线程状态切换图: 2. 协程 协程(纤程,用户级线程),英文Coroutines,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程可以拥有多个协程。 协程不是被操作系统内核所管理的,而是完全由程序所控制,也就是在用户态执行。 目的是为了追求最大力度的发挥硬件性能和提升软件的速度 基本原理是在某个点挂起当前的任务,并且保存栈信息,去执行另一个任 务;等完成或达到某个条件时,再还原原来的栈信息并继续执行(整个过程线程不需要上下文切换,所以不会像线程切换那样消耗资源)。 注意: Java不支持协程,在纯java代码里需要使用协程的话需要引入第三方包,如:quasar 3. 线程池 3.1 简介 线程池
  • Python asyncio异步编程 学习笔记
    跟着武沛齐老师教程做的学习笔记 主要参考:https://pythonav.com/wiki/detail/6/91/ 课程链接(《asyncio异步编程》,讲师:武沛齐老师) 文章目录 1 协程1.1 简介1.2 在Python中实现协程方式1.2.1 greenlet1.2.2 yield1.2.3 asyncio1.2.4 async & awit1.2.5 普通爬虫与协程爬虫1.2.5.1 普通爬虫(同步:按照顺序逐一排队执行)1.2.5.2 基于协程的异步编程实现(异步:遇到IO请求自动切换去发送其他任务请求) 2 异步编程2.1 事件循环2.2 async关键字(普通函数==>协程函数)2.3 await关键字(等)2.4 Tasks对象2.5 asyncio.Future对象2.6 concurrent.futures.Future对象 3 案例 asyncio + 不支持异步的模块(爬虫,如requests)4 异步迭代器5 异步上下文管理器6 事件循环升级 uvloop7 爬虫 1 协程 1.1 简介 协程,又称微线程,英文名Coroutine。 协程是一种用户态内的上下文切换技术。简而言之,就是通过一个线程实现代码块相互切换执行(协程可以利用IO等待的时间去执行一些其他的代码,从而提升代码执行效率。)。 协程是一种比线程更加轻量级的存在
  • 老树新花-Java异步服务开发
    https://v.qq.com/x/page/v0503qz6fdw.html 同步模型以前在并发量很低的情况下,是通过线程去收取数据并发送数据给客户端。但是当并发量和客户端连接数比较高的时候,服务器会出现明显的瓶颈。阻塞模型比较符合人的思考逻辑,但它会有线程阻塞的问题。阻塞模型会让出CPU,不适用于高并发。线程池或连接池只能解决一部分问题。因为线程池和连接池的本质作用并不是能直接提高QPS,而是减少或销毁线程的连接处以及开销。我们平时调用阻塞API的一个问题就在于单机的线程数是有限的。所以如果要提高服务端性能的话,首先就要去阻塞。异步模型异步阻塞模型处理I/O时大部分时间是非阻塞的(监听时除外),它调用的API会立即返回,这点是需要注意的。此外,处理结果的程序并不保证调用API当前的线程,这点在处理线程安全的问题上尤其要注意。Java中很多API都是基于操作系统底层API的模型,并没有做更高层次的封装。Java把一层阻塞异部I/O做了封装,这些就是Java或C语言异步模型的基石。少数线程等待事件发生,再根据对应类型处理相关事件。最近“协程”这个词比较火,看上去能解决异步模型的大部分问题。它是一个轻量级线程,可以直接当作线程来用。还能阻塞I/O API,阻塞的是协程而非线程。协程是用户态资源,用户态调度,消耗极低,可以启动数十万个协程。它的实现和线程不是1对1 的关系
  • 并发编程之Executor线程池原理与源码解读
    一、线程 线程是调度CPU资源的最小单位,线程模型分为KLT(内核态)模型与ULT(用户态)模型,JVM使用的KLT模型,Java线程与OS线程保持1:1的映射关系,也就是说有一个java线程也会在操作系统里有一个对应的线程。 Java线程生命状态 NEW,新建RUNNABLE,运行BLOCKED,阻塞WAITING,等待TIMED_WAITING,超时等待TERMINATED,终结 状态切换如下图所示: 二、协程 协程 (纤程,用户级线程),目的是为了追求最大力度的发挥硬件性能和提升软件的速度,协程基本原理是:在某个点挂起当前的任务,并且保存栈信息,去执行另一个任务;等完成或达到某个条件时,再还原原来的栈信息并继续执行(整个过程线程不需要上下文切换)。 Java原生不支持协程,在纯java代码里需要使用协程的话需要引入第三方包,如:quasar 三、线程池 “线程池”,顾名思义就是一个线程缓存,线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,因此Java中提供线程池对线程进行统一分配、调优和监控。 线程池介绍 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理。如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题: 如果并发的请求数量非常多,但每个线程执行的时间很短,这样就会频繁的创建和销毁线程
  • Kotlin协程
    1 概述 目录 前言 Kotlin协程,现在已经成为了面试甚至是工作中一个非常火的东西。 本人在刚开始了解Kotlin协程的时候,断断续续看了网上不少文章,用长篇大论把Kotlin协程描述的非常玄乎,但是看完后还是依然云里雾里,所以决定来写一篇关于协程的文章,希望能够帮助大家能够更快的上手Kotlin协程. 注意: 如果没有特殊提及,文中所有“协程”均代表“Kotlin协程” 2 为什么要学习Kotlin协程?(官方版) 现在Android技术栈上的新东西层出不穷,kotlin、jetpack、flutter等等。很多人是为了准备面试而学习,所以往往往更偏向于去看一些概念性的东西,以便面试的时候能够蒙混过关。 但是我觉得,我们还是先要了解这个新的技术能够给我们的开发带来哪些实质性的帮助,我们再去针对性学习可能会更加有意义. 我们先来看看Kotlin官网是怎么体现使用协程的优势的 https://www.kotlincn.net/docs/reference/coroutines/basics.html 网上很多文章也用这个例子,也用这个官方例子来说明使用协程的优势,然后就说协程是什么轻量级的线程,又是什么用户态的,协程像线程但又不是线程…诸如此类。 所以很多人自认为学会了协程,最后就可能只能说出来使用协程的目的是比线程性能更好。 先不说这些概念对不对
  • 阿里P8大佬带你真正理解一波Kotlin协程
    1概述 目录 前言 Kotlin协程,现在已经成为了面试甚至是工作中一个非常火的东西。 本人在刚开始了解Kotlin协程的时候,断断续续看了网上不少文章,用长篇大论把Kotlin协程描述的非常玄乎,但是看完后还是依然云里雾里,所以决定来写一篇关于协程的文章,希望能够帮助大家能够更快的上手Kotlin协程. 注意:如果没有特殊提及,文中所有“协程”均代表“Kotlin协程” 2为什么要学习Kotlin协程?(官方版) 现在Android技术栈上的新东西层出不穷,kotlin、jetpack、flutter等等。很多人是为了准备面试而学习,所以往往往更偏向于去看一些概念性的东西,以便面试的时候能够蒙混过关。 但是我觉得,我们还是先要了解这个新的技术能够给我们的开发带来哪些实质性的帮助,我们再去针对性学习可能会更加有意义. 我们先来看看Kotlin官网是怎么体现使用协程的优势的 https://www.kotlincn.net/docs/reference/coroutines/basics.html 网上很多文章也用这个例子,也用这个官方例子来说明使用协程的优势,然后就说协程是什么轻量级的线程,又是什么用户态的,协程像线程但又不是线程...诸如此类。 所以很多人自认为学会了协程,最后就可能只能说出来使用协程的目的是比线程性能更好。 先不说这些概念对不对