首页 > 系统相关 >多进程多线程记录第一篇

多进程多线程记录第一篇

时间:2022-11-09 14:25:45浏览次数:74  
标签:__ main name 第一篇 线程 进程 多线程 def

多线程与多进程

一, 什么是进程, 什么是线程?

​ 进程: 运行中的程序. 每次我们执行一个程序, 咱们的操作系统对自动的为这个程序准备一些必要的资源(例如, 分配内存, 创建一个能够执行的线程. )

​ 线程: 程序内, 可以直接被CPU调度的执行过程. 是操作系统能够进行运算调度的最小单位. 它被包含在进程之中, 是进程中的实际运作单位.

​ 进程与线程之间的关系:

​ 进程是资源单位(公司). 线程是执行单位(员工). 就好比是一家公司. 一家公司的资源就是桌椅板凳, 电脑饮水机这些资源, 但是, 我们如果说一家公司正在运转着, 运行着. 那里面必须要有能为这家公司工作的人. 程序里面也一样, 进程就是为了程序运行而需要的各种资源. 但是程序想要运行, 就必须由线程来被CPU调度执行.

​ 我们运行的每一个程序默认都会有一个线程. 哪怕是只有helloworld级别的程序. 想要执行. 也会有一个线程产生.

如何提高一家公司的产能效率

二, 多线程

​ 顾名思义, 多线程就是让程序产生多个线程一起去执行. 还拿公司举例子. 一家公司里如果只有一个员工, 工作效率肯定不会高到哪里去. 怎么提高效率? 多招点儿人就OK了.

1. 直接用Thread创建线程

我们先看看单线程的效果

def func():
    for i in range(1000):
        print("func", i)


if __name__ == '__main__':
    func()
    for i in range(1000):
        print("main", i)

再看多线程

from threading import Thread


def func():
    for i in range(1000):
        print("func", i)


if __name__ == '__main__':
    t = Thread(target=func)
    t.start()
    for i in range(1000):
        print("main", i)

2. 线程池

python还提供了线程池功能. 可以一次性的创建多个线程, 并且, 不需要我们程序员手动去维护. 一切都交给线程池来自动管理.

# 线程池
def fn(name):
    for i in range(1000):
        print(name, i)


if __name__ == '__main__':
    with ThreadPoolExecutor(10) as t:
        for i in range(100):
            t.submit(fn, name=f"线程{i}")

如果任务有返回值怎么办?

def func(name):
    time.sleep(2)
    return name


def do_callback(res):
    print(res.result())


if __name__ == '__main__':
    with ThreadPoolExecutor(10) as t:
        names = ["线程1", "线程2", "线程3"]
        for name in names:
            # 方案一, 添加回调
            t.submit(func, name).add_done_callback(do_callback)

            
if __name__ == '__main__':
    start = time.time()
    with ThreadPoolExecutor(10) as t:
        names = [5, 2, 3]
        # 方案二, 直接用map进行任务分发. 最后统一返回结果
        results = t.map(func, names)  # 结果是按照你传递的顺序来执行的, 代价就是如果第一个没结束. 后面就都没结果
        for r in results:
            print("result", r)
    print(time.time() - start)

3. 多线程在爬虫中的应用

http://www.boxofficecn.com/boxofficecn

我们抓取从1994年到2021年的电影票房.

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


def get_page_source(url):
    resp = requests.get(url)
    resp.encoding = 'utf-8'
    return resp.text


def parse_html(html):
    try:
        tree = etree.HTML(html)
        trs = tree.xpath("//table/tbody/tr")[1:]
        result = []
        for tr in trs:
            year = tr.xpath("./td[2]//text()")
            year = year[0] if year else ""
            name = tr.xpath("./td[3]//text()")
            name = name[0] if name else ""
            money = tr.xpath("./td[4]//text()")
            money = money[0] if money else ""
            d = (year, name, money)
            if any(d):
                result.append(d)
        return result
    except Exception as e:
        print(e)  # 调bug专用


def download_one(url, f):
    page_source = get_page_source(url)
    data = parse_html(page_source)
    for item in data:
        f.write(",".join(item))
        f.write("\n")


def main():
    f = open("movie.csv", mode="w", encoding='utf-8')
    lst = [str(i) for i in range(1994, 2022)]
    with ThreadPoolExecutor(10) as t:
        # 方案一
        # for year in lst:
        #     url = f"http://www.boxofficecn.com/boxoffice{year}"
        #     # download_one(url, f)
        #     t.submit(download_one, url, f)

        # 方案二
        t.map(download_one, (f"http://www.boxofficecn.com/boxoffice{year}" for year in lst), (f for i in range(len(lst))))


if __name__ == '__main__':
    main()

三, 多进程

一个公司能创造的价值毕竟是有限的. 怎么办? 开分公司啊. 此所谓多进程. python实现多进程的方案和多线程几乎一样. 非常的简单

1. 直接用Process创建进程

def func():
    for i in range(1000):
        print("func", i)


if __name__ == '__main__':
    p = Process(target=func)
    p.start()

    for i in range(1000):
        print("main", i)

2. 多进程在爬虫中的应用

​ 如果遇到图片抓取的时候, 我们知道图片在一般都在网页的img标签中src属性存放的是图片的下载地址. 此时我们可以采用多进程的方案来实现, 一个负责疯狂扫图片下载地址. 另一个进程只负责下载图片.

​ 综上, 多个任务需要并行执行, 但是任务之间相对独立(不一定完全独立). 可以考虑用多进程.

from multiprocessing import Process,Queue
from concurrent.futures import ThreadPoolExecutor
from lxml import etree

import requests
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36"
}

def get_img_src(q):
    """
    进程1: 负责提取页面中所有的img的下载地址
    将图片的下载地址通过队列. 传输给另一个进程进行下载
    """
    for i in range(1, 11):
        url = f"https://www.pkdoutu.com/photo/list/?page={i}"
        resp = requests.get(url, headers=headers)
        tree = etree.HTML(resp.text)
        srcs = tree.xpath("//li[@class='list-group-item']//img[@referrerpolicy='no-referrer']/@data-original")
        for src in srcs:
            q.put(src.strip())
        resp.close()
    q.put("ok")


def download_img(q):
    """
        进程2: 将图片的下载地址从队列中提取出来. 进行下载.
   """
    with ThreadPoolExecutor(20) as t:
        while 1:
            s = q.get()
            if s == 'ok':
                break
            t.submit(donwload_one, s)

def donwload_one(s):
    # 单纯的下载功能
    resp = requests.get(s, headers=headers)
    file_name = s.split("/")[-1]
    # 请提前创建好img文件夹
    with open(f"img/{file_name}", mode="wb") as f:
        f.write(resp.content)
    print("一张图片下载完毕", file_name)
    resp.close()

if __name__ == '__main__':
    q = Queue()  # 两个进程必须使用同一个队列. 否则数据传输不了
    p1 = Process(target=get_img_src, args=(q,))
    p2 = Process(target=download_img, args=(q,))
    p1.start()
    p2.start()

记住一个事情就好. 多进程相当于多个程序. 多线程相当于在一个程序里多条任务同时执行.

标签:__,main,name,第一篇,线程,进程,多线程,def
From: https://www.cnblogs.com/woyaofei/p/16873438.html

相关文章

  • 读者-写者(多线程)
    0推荐在openEuer上实现1描述操作系统中“读者-写者”问题,理解问题的本质,提交你理解或查找到的文本资料2利用多线程完成reader和writer3在main中测试若干个reade......
  • 线程同步-读者写者问题(多线程)
    多线程通信之读者、写者问题读、写问题是另一个非常出名的同步问题,常常用来模拟数据库的数据查询和数据修改两种情况问题。也即,一个数据库允许有多个访问者同时对其进行......
  • WinForm中的多线程
    使用BeginInvoke或Invoke作用在自己创建的非UI线程中,进行UI操作,比如更新UI上控件的状态。Windows窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一......
  • 多线程的操作方式
    MAX_PRIOITY10 MIN_PRIOITY 1NORM_PRIOITY 5  getPriority();返回线程的优先级setPriority(intnewPriority)改变线程的优先级......
  • 尚硅谷java入门b站零基础 异常处理 +多线程+部分项目三 2022.3.26
    380如何自定义异常/**如何自定义异常类?*1.继承于现有的异常结构:RuntimeException、Exception*2.提供全局常量:serialVersionUID*3.提供重载的构造器**/publicc......
  • 线程同步-读者写者问题(多线程)
    任务描述:0推荐在openEuer上实现1描述操作系统中“读者-写者”问题,理解问题的本质,提交你理解或查找到的文本资料2利用多线程完成reader和writer3在main中测试若干个......
  • linux 进程管理
    Linux进程管理linux中每一个运行中的程序叫做进程,每个运行中的进程都会分配一个ID号大多系统进程运行在后台,常驻在系统中直到关机才会结束查看Linux的系统进程ps$ps......
  • Linux多线程开发
    1.线程线程概述与进程(process)类似,线程(thread)是允许应用程序并发执行多个任务的一种机制。一个进程可以包含多个线程。同一个程序中的所有线程均会独立执行相同程序,且共享......
  • 【操作系统】02-进程的描述与控制
    计算机操作系统——进程目录计算机操作系统——进程第二章进程的描述与控制2.1前趋图和程序执行2.1.1前趋图(PrecedenceGraph)2.1.2程序顺序执行2.1.3程序并发执行......
  • Linux系统编程——进程控制
    在学习Linux系统编程总结了笔记,并分享出来。09-linux-day05(进程控制)目录:一、学习目标二、进程1、进程和程序2、单道和多道程序设计3、进程的状态转化4、MMU的作用5、PCB......