首页 > 其他分享 >多线程

多线程

时间:2024-05-22 13:18:45浏览次数:12  
标签:task img self 线程 time 进程 多线程

【一】什么是线程

在操作系统中,每一个进程都有一块内存空间地址,你的程序就泡在这块内存地址上

不可能一个程序只有一个进程在处理所有数据和逻辑

于是就有了线程这个概念:在进程内部开设的处理程序的进程

操作系统 --> 运行一个程序叫进程 ---> 进程里面又开了一个进程 ---> 改名叫线程

进程只是用来将所有资源总结起来的单位,线程才是CPU上的执行单位

多线程就是在进程CPU处理多个任务的逻辑

例子

进程就是你的资源单位 就是车间 ---> 存储设备及资源

线程就是你的执行单位 就是流水线 --> 负责对数据进行加工和处理

注意

进程和线程都是抽象的概念

【二】进程和线程创建的开销问题

进程的创建开销 > 线程的创建开销

比如一个软件就是一个工厂

工厂内部有很多流水线

流水线工作需要资源(基于电工作)

电源就是 一个CPU

一个车间就是一个进程 一个车间内部至少会有一个线程(流水线)

创建进程 ---> 相当于你要创建一个车间 ---> 选地,买设备

创建线程 --> 有了车间,只需要增加流水线 --> 减少了开销

【三】进程和线程之间的关系

进程与进程之间的关系是竞争关系

在同一块 内存中抢占内存空间 ---> 内存空间越大你的程序跑的可能就越快

线程与线程之间的关系是协作关系

线程是在同一块进程之下的工友

不能自己干自己

百度网盘下载内容的时候 5 个下载明额 10 个

【四】进程和线程的区别

● Threads share the address space of the process that created it; processes have their own address space.

○ 线程共享创建它的进程的地址空间; 进程具有自己的地址空间。

● Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.

○ 线程可以直接访问其进程的数据段; 进程具有其父进程数据段的副本。

● Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.

○ 线程可以直接与其进程中的其他线程通信; 进程必须使用进程间通信与同级进程进行通信。

● New threads are easily created; new processes require duplication of the parent process.

○ 新线程很容易创建; 新进程需要复制父进程。

● Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.

○ 线程可以对同一进程的线程行使相当大的控制权。 进程只能控制子进程。

● Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.

○ 对主线程的更改(取消,优先级更改等)可能会影响该进程其他线程的行为; 对父进程的更改不会影响子进程。

开设多进程的时候每一个进程之间的数据是相互隔离的

每一个人都有 1 没一人都该 0

对于多线程来说,所有线程共享一个进程中的数据

只有一个 1 0 -1 -2 -3

思考题

(1)案例需求:

开发一款文字处理软件 --- 进程还是线程 进程

● 获取用户输入的功能 --- 进程还是线程 线程

● 实时展示到屏幕的功能 --- 进程还是线程 线程

● 自动保存数据到硬盘的功能 --- 进程还是线程 线程

每一个功能应该做成进程还是线程

● 开启一个文字处理软件 进程

● 该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘

● 这三个任务操作的都是同一块数据,因而不能用多进程。

● 只能在一个进程里并发地开启三个线程

● 如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。

多进程和多线程只有在遇到阻塞的时候才能体现出速度快,如果没有阻塞,就没有效率

【一】threading模块介绍

from threading import Thread
import time
import random
import os

class MyThread(Thread):
def init(self, name, args, **kwargs):
super().init(
args, **kwargs)
self.name = name

def run(self):
    print(f'{self.name} is starting  .... ')
    sleep_time = random.randint(1, 5)
    print(f'{self.name} is start sleep time is {sleep_time}s  .... ')
    time.sleep(sleep_time)
    print(f'{self.name} is end sleep time is {sleep_time}s  .... ')
    print(f'{self.name} is ending  .... ')

计算 1+ 100

直接通过代码运行快 直接通过内存

还是通过多进程快/多线程快 :打开文件

【1】方式一:通过线程的对象来开启多线程

def work(name):
print(f'{name} is starting .... ')
print(f'thread {name} pid is {os.getpid()} ppid is {os.getppid()} .... ')
sleep_time = random.randint(1, 5)
print(f'{name} is start sleep time is {sleep_time}s .... ')
time.sleep(sleep_time)
print(f'{name} is end sleep time is {sleep_time}s .... ')
print(f'{name} is ending .... ')

def main():
task_list = []
for i in range(5):
task = Thread(
target=work,
args=('thread-{}'.format(i),)
)
task.start()
task_list.append(task)
[task.join() for task in task_list]

def main_one():
task_list = []
for i in range(5):
task = MyThread(name='thread-{}'.format(i))
task.start()
task_list.append(task)
[task.join() for task in task_list]

if name == 'main':
print(f'main process pid is {os.getpid()} ppid is {os.getppid()} .... ')
print(f'main process start .... ')
start_time = time.time()
main()
# main_one()
end_time = time.time()
print(f'main process end .... ')
print(f'总耗时 :>>>> {end_time - start_time}s')

# main process pid is 313892 ppid is 280184 ....

# thread thread-0 pid is 313892 ppid is 280184  ....

线程共享数据
from threading import Thread
from multiprocessing import Process

number = 999

def work(name):
global number
print(f'{name} change before {number}')
number += 1
print(f'{name} change after {number}')

def main_process():
task_list = []
for i in range(5):
task = Process(
target=work,
args=(f'process_{i}',)
)
task.start()
task_list.append(task)
[task.join() for task in task_list]
print(number)

def main_thread():
task_list = []
for i in range(5):
task = Thread(
target=work,
args=(f'thread_{i}',)
)
task.start()
task_list.append(task)
[task.join() for task in task_list]
print(number)

if name == 'main':
# main_process()
main_thread()

# thread_0 change before 999
# thread_0 change after 1000
# thread_1 change before 1000
# thread_1 change after 1001
# thread_2 change before 1001
# thread_2 change after 1002
# thread_3 change before 1002
# thread_3 change after 1003
# thread_4 change before 1003
# thread_4 change after 1004
# 1004

多线程比多进程快
import time

【一】需要两个模块

【1】模仿浏览器对网址发起请求

import requests # pip install requests

【2】解析页面数据的模块

from lxml import etree # pip install lxml

【3】模仿浏览器

from fake_useragent import UserAgent # pip install fake-useragent

from multiprocessing import Process
from threading import Thread

【二】解析网页请求及数据

class SpiderImg(object):
def init(self):
self.base_area = 'https://pic.netbian.com'
self.base_url = 'https://pic.netbian.com/4kdongman/'
self.headers = {
'User-Agent': UserAgent().random
}

def spider_tag_url(self):
    img_data_dict = {}
    response = requests.get(self.base_url, headers=self.headers)
    # response.encoding = 'utf-8'
    response.encoding = 'gbk'
    page_text = response.text
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//*[@id="main"]/div[4]/ul/li')
    for li in li_list:
        # //*[@id="main"]/div[4]/ul/li[1]/a
        # ./a
        detail_href = self.base_area + li.xpath('./a/@href')[0]
        response = requests.get(detail_href, headers=self.headers)
        response.encoding = 'gbk'
        page_text = response.text
        tree = etree.HTML(page_text)
        img_url = self.base_area + tree.xpath('//*[@id="img"]/img/@src')[0]
        # https://pic.netbian.com/uploads/allimg/240521/232729-17163052491e1c.jpg
        img_title = img_url.split('/')[-1]
        # 240521/232729-17163052491e1c.jpg
        img_data_dict[img_title] = img_url
    return img_data_dict

def download_img(self, img_url, img_title):
    # 获取到图片的二进制数据
    response = requests.get(img_url, headers=self.headers)
    img_data = response.content
    with open(f'{img_title}', 'wb') as fp:
        fp.write(img_data)
    print(f'当前下载 {img_title} 成功!')

def main_process(self):
    start_time = time.time()
    img_data_dict = self.spider_tag_url()
    end_time = time.time()
    print(f'抓取所有图片连接数据 {len(img_data_dict)} 总耗时 :>>>> {end_time - start_time}s')
    task_list = []
    for img_title, img_url in img_data_dict.items():
        task = Process(
            target=self.download_img,
            kwargs={'img_url': img_url, 'img_title': img_title}
        )
        task.start()
        task_list.append(task)
    for task in task_list:
        task.join()

def main_thread(self):
    start_time = time.time()
    img_data_dict = self.spider_tag_url()
    end_time = time.time()
    print(f'抓取所有图片连接数据  {len(img_data_dict)}  总耗时 :>>>> {end_time - start_time}s')
    task_list = []
    for img_title, img_url in img_data_dict.items():
        task = Thread(
            target=self.download_img,
            kwargs={'img_url': img_url, 'img_title': img_title}
        )
        task.start()
        task_list.append(task)
    for task in task_list:
        task.join()

if name == 'main':
spider = SpiderImg()
start_time = time.time()
# spider.main_process() # 下载所有图片总耗时 :>>>> 7.990673542022705s
spider.main_thread() # 下载所有图片总耗时 :>>>> 5.58322811126709s
end_time = time.time()
print(f'下载所有图片总耗时 :>>>> {end_time - start_time}s')

标签:task,img,self,线程,time,进程,多线程
From: https://www.cnblogs.com/zenopan101861/p/18206055

相关文章

  • C++ 多线程编程要点总结
    C++多线程编程要点总结:选择合适的线程库:C++11引入了 <thread> 头文件,提供了对线程的原生支持。也可以使用第三方库,如Boost.Thread,它提供了更多高级功能和更好的跨平台兼容性。线程创建与管理:使用 std::thread 类创建新线程,并传入函数或可调用对象作为线程的入口......
  • 多线程和多进程 - 初窥
    一、说明在平常工作中,我们使用top命令查看一台linux服务器的cpu使用情况时,会发现某个进程的cpu使用率会超过100%,这是为什么?二、举例实验环境为CentOS7.6+Python2.71.多线程、多进程在操作系统中的表现形式我们首先看两个例子,test1.py和test2.py,都是执行死循环,test1.py两......
  • PHP的多样化执行方式(parallel PHP多线程实现,原生协程实现,多进程实现,ZTS、NTS、TS又是
    进程、线程、协程进程:应用程序的启动实例,运行起的代码叫进程,有独立的内存空间,类比工厂的P个(P=1单进程,P>1多进程)车间。线程:线程是CPU调度的最小单位,是进程内的执行单元,多个线程共享所属进程的资源。类比车间内的T个员工(T=1单线程,T>1多线程)车间。协程:类似线程,协程是用户态(CPU受......
  • 多线程下使用List中的subList和remove方法产生的 java.util.ConcurrentModificationEx
    在说多线程操作List之前,我们先看下单线程下产生的问题:单线程List<Integer>listA=newArrayList<>();listA.add(1);listA.add(2);listA.add(3);listA.add(4);listA.add(5);listA.add(6);for(Integera:listA){......
  • 超线程/同步多线程(HT/SMT)技术
    超线程/同步多线程(HT/SMT)技术虽然现在超线程(Hyper-Threading)被大家广泛接受,并把所有一个物理核心上有多个虚拟核心的技术都叫做超线程,但这其实是Intel的一个营销名称。而实际上这一类技术的(学术/技术)通行名称是同步多线程(SMT,SimultaneousMultithreading)技术。SMT技术初衷是通......
  • Python 内置库 多线程threading使用讲解
    线程基本使用单线程defmain():print("在扔一个苹果")if__name__=="__main__":main()多线程Python提供了thread、threading等模块来进行线程的创建与管理,后者在线程管理能力上更进一步,因此我们通常使用threading模块。创建一个线程需要指定该线程执行的任务(函......
  • 多线程循环控制字段失效造成死循环的坑
    编程的时候遇到一个场景:A,B两个线程,B是一个while(flag),有个控制字段flag,刚开始是trueB会一直循环,A某个情况回把flag置为false,但是如果B的循环里什么都没干,就一直不退出,陷入死循环本来以为是哪里逻辑写错了,于是在B里面加入了一个printf,没想到结果就能正常退出了 ......
  • N1CTF2018 shopping:多线程堆题中堆溢出的应用
    介绍一种在多线程堆题中利用堆溢出达成任意地址分配的手法。我们知道,一个进程的主线程的堆管理main_arena在libc中,分配的chunk在堆段中。那么子线程的arena和堆块都在哪里呢?这一大串在libc前面一点点的anon就是给子线程留的arena和堆空间。arena和tcache管理chunk在这个内存段......
  • C#异步与多线程
    c#的异步与多线程异步与多线程首先,异步是相对于同步的一个概念,在同步环境下,程序允许至某处需要等待的位置,会发生阻塞,直到达到条件才会继续向下运行;而异步操作则可以在需要等待的位置,跳过等待,执行其他内容,通常异步处理的事务不能相互存在影响。多线程指的是,同时使用多个线程执行......
  • mybatis多线程插入数据表已经事务回滚
    importlombok.extern.slf4j.Slf4j;importorg.apache.commons.collections4.CollectionUtils;importorg.apache.commons.collections4.ListUtils;importorg.apache.ibatis.session.ExecutorType;importorg.apache.ibatis.session.SqlSession;importorg.apache.ibati......