Qt扫盲-Qt Concurrent概述

Qt Concurrent概述

  • 一、概述
  • 二、Concurrent Map 和 Map- reduce
    • 1. 并发 Map
    • 2. 并发 Map-Reduce
    • 3. 其他API特性
      • 1. 使用迭代器而不是Sequence
      • 3. 阻塞变量
      • 4. 使用成员函数
      • 5. 使用函数对象
      • 6. 包装接受多个参数的函数
  • 三、Concurrent Filter and Filter-Reduce
    • 1. 并发过滤器
    • 2. 并发Filter-Reduce
    • 3. 其他API特性
      • 1. 使用迭代器而不是Sequence
      • 2. 使用成员函数
      • 3. 使用函数对象
      • 4. 包装接受多个参数的函数
  • 四、Concurrent Run
    • 1. 在单独的线程中运行函数
    • 2. 向函数传递参数
    • 3. 从函数返回值
    • 4. 其他API特性
      • 1. 使用成员函数
      • 2. 使用Lambda函数

一、概述

QtConcurrent 命名空间提供了一些高级api,可以在不使用互斥锁、读写锁、等待条件或信号量等低级线程原语的情况下编写多线程程序。使用QtConcurrent编写的程序会根据可用的处理器核数自动调整所使用的线程数。这意味着今天编写的应用程序在将来部署到多核系统上时将继续扩展。

QtConcurrent包括用于并行列表处理的函数式编程风格api,包括用于共享内存(非分布式)系统的 MapReduce 和 FilterReduce 实现,以及用于管理GUI应用程序中的异步计算的类:

  • Concurrent Map 和 Map- reduce
    QtConcurrent::map() 对容器中的每个项应用一个函数,就地修改这些项 (不返回,原地修改)
    QtConcurrent::mapped() 类似于map(),不同之处在于它返回一个带有修改的新容器 (返回修改)
    QtConcurrent::mappedReduced() 类似于map(),不同之处在于修改后的结果被简化或折叠为单个结果。
  • Concurrent Filter和Filter- reduce
    QtConcurrent::filter() 根据过滤器函数的结果从容器中删除所有项。
    QtConcurrent::filtered() 类似于filter(),不同之处在于它返回一个包含过滤结果的新容器。
    QtConcurrent::filteredReduced() 类似于filtered(),不同之处在于过滤后的结果被简化或折叠为单个结果。
  • 并发运行 (Concurrent Run)
    QtConcurrent::run() 在另一个线程中运行函数。
  • QFuture 表示异步计算的结果。
  • QFutureIterator 允许通过QFuture得到的结果进行迭代。
  • QFutureWatcher 允许使用信号和插槽监控QFuture。
  • QFutureSynchronizer 是一个方便的类,可以自动同步多个QFutures。

Qt Concurrent 支持几种与 stl 兼容的容器和迭代器类型,但最适合具有随机访问迭代器的Qt容器,如 QList 或 QVector。map 和 filter 函数接受容器和 begin/end 迭代器。

STL迭代器支持概述:

迭代器类型示例类支持状态
输入迭代器不支持
输出迭代器不支持
前向迭代器std:: slist支持
双向迭代器QLinkedList, std::list支持
随机存取迭代器QList, QVector, std::vector支持和推荐

在Qt Concurrent迭代大量轻量级项的情况下,随机访问迭代器可以更快,因为它们允许跳转到容器中的任何点。此外,使用随机访问迭代器允许 Qt Concurrent 通过 QFuture::progressValue() 和 QFutureWatcher::progressValueChanged() 提供进度信息。

非就地修改函数,如 mapped() 和 filtered(),在调用时生成一个容器的副本。如果使用STL容器,此复制操作可能需要一些时间,在这种情况下,Qt 建议为容器指定 开始和结束 迭代器。

二、Concurrent Map 和 Map- reduce

QtConcurrent::map()、QtConcurrent::mapped()和QtConcurrent::mappedReduced()函数对序列(如QList或QVector)中的项并行运行计算。QtConcurrent::map()就地修改序列,QtConcurrent::mapped()返回一个包含修改内容的新序列,而QtConcurrent::mappedReduced()返回一个结果。

这些函数是Qt Concurrent框架的一部分。

上面的每个函数都有一个阻塞变量,它返回最终结果而不是 QFuture。我们可以像使用异步变量一样使用它们。

  QList<QImage> images = ...;// Each call blocks until the entire operation is finished.QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);QtConcurrent::blockingMap(images, scale);QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

注意,上面的结果类型不是QFuture对象,而是真正的结果类型(在本例中是QList和QImage)。

1. 并发 Map

QtConcurrent::mapped() 接受输入序列和映射函数。然后对序列中的每一项调用该映射函数,并返回一个包含映射函数返回值的新序列。

map函数的格式必须是:

 U function(const T &t);

T 和 U可以是任何类型(它们甚至可以是相同的类型),但是T必须匹配存储在序列中的类型。函数返回修改或映射的内容。

这个例子展示了如何将一个比例函数应用于一个序列中的所有项:

  QImage scaled(const QImage &image){return image.scaled(100, 100);}QList<QImage> images = ...;QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);

该 Map 的结果可通过QFuture获得。有关如何在应用程序中使用QFuture的更多信息,请参阅QFuture和QFutureWatcher文档。

如果我们想就地修改序列,请使用QtConcurrent::map()。map函数必须是这样的形式:

 U function(T &t);

注意,没有使用map函数的返回值和返回类型。

使用QtConcurrent::map()类似于使用QtConcurrent::mapped():

  void scale(QImage &image){image = image.scaled(100, 100);}QList<QImage> images = ...;QFuture<void> future = QtConcurrent::map(images, scale);

由于序列被就地修改,QtConcurrent::map()不会通过QFuture返回任何结果。但是,我们仍然可以使用QFuture和QFutureWatcher来监视 Map 的状态。

2. 并发 Map-Reduce

QtConcurrent::mappedReduced()类似于QtConcurrent::mapped(),但不是返回带有新结果的序列,而是使用reduce函数将结果组合成单个值。

QFuture<ResultType> QtConcurrent:: mapappedreduced (const Sequence &sequence, MapFunctor mapFunction, ReduceFunctor reduceFunction, QtConcurrent::ReduceOptions ReduceOptions = ReduceOptions(UnorderedReduce | SequentialReduce))

含义:按顺序为每个Item 调用mapFunction一次。每个mapFunction的返回值传递给reduceFunction,最后获得一个结果。

reduce函数的形式必须是:

V function(T &result, const U &intermediate)

T是最终结果的类型,U是映射函数的返回类型。注意,这里没有使用reduce函数的返回值和返回类型。

像这样调用QtConcurrent::mappedReduced():

  void addToCollage(QImage &collage, const QImage &thumbnail){QPainter p(&collage);static QPoint offset = QPoint(0, 0);p.drawImage(offset, thumbnail);offset += ...;}QList<QImage> images = ...;QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);

对于map函数返回的每个结果,reduce函数将被调用一次,并且应该将中间值合并到result变量中。

QtConcurrent::mappedReduced() 保证一次只有一个线程调用reduce,所以没有必要使用互斥锁来锁定结果变量。

ReduceOptions enum提供了一种方法来控制执行缩减的顺序。如果使用QtConcurrent::UnorderedReduce(默认值),则顺序是未定义的,而QtConcurrent::OrderedReduce确保按原始序列的顺序进行缩减。

3. 其他API特性

1. 使用迭代器而不是Sequence

以上每个函数都有一个变体,它接受迭代器范围而不是序列。使用它们的方式与序列变体相同:

QList<QImage> images = ...;QFuture<QImage> thumbnails = QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);// Map in-place only works on non-const iterators.
QFuture<void> future = QtConcurrent::map(images.begin(), images.end(), scale);QFuture<QImage> collage = QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);

3. 阻塞变量

上面的每个函数都有一个阻塞变量,它返回最终结果而不是QFuture。我们可以像使用异步变量一样使用它们。

  QList<QImage> images = ...;// Each call blocks until the entire operation is finished.QList<QImage> future = QtConcurrent::blockingMapped(images, scaled);QtConcurrent::blockingMap(images, scale);QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

注意,上面的结果类型不是QFuture对象,而是真正的结果类型(在本例中是QList和QImage)。

4. 使用成员函数

QtConcurrent::map()、QtConcurrent::mapped()和QtConcurrent::mappedReduced()接受指向成员函数的指针。成员函数类类型必须与序列中存储的类型匹配:

  // Squeeze all strings in a QStringList.QStringList strings = ...;QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);// Swap the rgb values of all pixels on a list of images.QList<QImage> images = ...;QFuture<QImage> bgrImages = QtConcurrent::mapped(images, &QImage::rgbSwapped);// Create a set of the lengths of all strings in a list.QStringList strings = ...;QFuture<QSet<int> > wordLengths = QtConcurrent::mappedReduced(strings, &QString::length, &QSet<int>::insert);

注意,当使用QtConcurrent::mappedReduced()时,你可以自由地混合使用普通函数和成员函数:

  // Can mix normal functions and member functions with QtConcurrent::mappedReduced().// Compute the average length of a list of strings.extern void computeAverage(int &average, int length);QStringList strings = ...;QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage);// Create a set of the color distribution of all images in a list.extern int colorDistribution(const QImage &string);QList<QImage> images = ...;QFuture<QSet<int> > totalColorDistribution = QtConcurrent::mappedReduced(images, colorDistribution, QSet<int>::insert);

5. 使用函数对象

QtConcurrent::map()、QtConcurrent::mapped()和QtConcurrent::mappedReduced()接受map函数的函数对象。这些函数对象可用于向函数调用添加状态。result_type typepedef必须定义函数调用操作符的结果类型:

  struct Scaled{Scaled(int size): m_size(size) { }typedef QImage result_type;QImage operator()(const QImage &image){return image.scaled(m_size, m_size);}int m_size;};QList<QImage> images = ...;QFuture<QImage> thumbnails = QtConcurrent::mapped(images, Scaled(100));

对于reduce函数,不直接支持函数对象。但是,当显式指定了缩减结果的类型时,可以使用函数对象:

  struct ImageTransform{void operator()(QImage &result, const QImage &value);};QFuture<QImage> thumbNails =QtConcurrent::mappedReduced<QImage>(images,Scaled(100),ImageTransform(),QtConcurrent::SequentialReduce);

6. 包装接受多个参数的函数

如果我们想使用接受多个参数的map函数,可以使用lambda函数或std::bind()将其转换为接受一个参数的函数。
作为示例,我们将使用QImage::scaledToWidth():

  QImage QImage::scaledToWidth(int width, Qt::TransformationMode) const;

scaledToWidth接受三个参数(包括“this”指针),不能直接与QtConcurrent::mapped()一起使用,因为QtConcurrent::mapped()期望一个函数接受一个参数。为了使用QImage::scaledToWidth()和QtConcurrent::mapped(),我们必须提供一个宽度和转换模式的值:

  QList<QImage> images = ...;std::function<QImage(const QImage &)> scale = [](const QImage &img) {return img.scaledToWidth(100, Qt::SmoothTransformation);};QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scale);

三、Concurrent Filter and Filter-Reduce

QtConcurrent::filter()、QtConcurrent::filtered()和QtConcurrent::filteredReduced()函数对序列中的项进行并行过滤,比如QList或QVector。QtConcurrent::filter()就地修改序列,QtConcurrent::filtered()返回包含过滤内容的新序列,QtConcurrent::filteredReduced()返回单个结果。
这些函数是Qt Concurrent框架的一部分。
上面的每个函数都有一个阻塞变量,它返回最终结果而不是QFuture。您可以像使用异步变体一样使用它们。

  QStringList strings = ...;// each call blocks until the entire operation is finishedQStringList lowerCaseStrings = QtConcurrent::blockingFiltered(strings, allLowerCase);QtConcurrent::blockingFilter(strings, allLowerCase);QSet<QString> dictionary = QtConcurrent::blockingFilteredReduced(strings, allLowerCase, addToDictionary);

注意,上面的结果类型不是QFuture对象,而是真正的结果类型(在本例中是QStringList和QSet)。

1. 并发过滤器

QtConcurrent::filtered()接受一个输入序列和一个过滤函数。然后对序列中的每个项调用此筛选函数,并返回一个包含筛选值的新序列。

过滤器函数必须是这样的:

bool function(const T &t);

T必须匹配存储在序列中的类型。如果应该保留该项,则返回true;如果应该丢弃该项,则返回false。

这个例子展示了如何从QStringList中保留所有小写的字符串:

  bool allLowerCase(const QString &string){return string.lowered() == string;}QStringList strings = ...;QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings, allLowerCase);

过滤器的结果可以通过QFuture获得。有关如何在应用程序中使用QFuture的更多信息,请参阅QFuture和QFutureWatcher文档。

如果你想就地修改一个序列,使用QtConcurrent::filter():

  QStringList strings = ...;QFuture<void> future = QtConcurrent::filter(strings, allLowerCase);

由于序列被就地修改,QtConcurrent::filter()不会通过QFuture返回任何结果。但是,您仍然可以使用QFuture和QFutureWatcher来监视过滤器的状态。

2. 并发Filter-Reduce

QtConcurrent::filteredReduced()类似于QtConcurrent::filtered(),但不是返回一个包含过滤结果的序列,而是使用reduce函数将结果组合成一个值。

reduce函数的形式必须是:

V function(T &result, const U &intermediate)

T是最终结果的类型,U是被过滤项目的类型。注意,这里没有使用reduce函数的返回值和返回类型。

像这样调用QtConcurrent::filteredReduced():

  void addToDictionary(QSet<QString> &dictionary, const QString &string){dictionary.insert(string);}QStringList strings = ...;QFuture<QSet<QString> > dictionary = QtConcurrent::filteredReduced(strings, allLowerCase, addToDictionary);

对于过滤器函数保存的每个结果,reduce函数将被调用一次,并且应该将中间结果合并到结果变量中。

QtConcurrent::filteredReduced()保证一次只有一个线程调用reduce,所以没有必要使用互斥锁来锁定结果变量。ReduceOptions enum提供了一种方法来控制执行缩减的顺序。

3. 其他API特性

1. 使用迭代器而不是Sequence

以上每个函数都有一个变体,它接受迭代器范围而不是序列。使用它们的方式与序列变体相同:

  QStringList strings = ...;QFuture<QString> lowerCaseStrings = QtConcurrent::filtered(strings.constBegin(), strings.constEnd(), allLowerCase);// filter in-place only works on non-const iteratorsQFuture<void> future = QtConcurrent::filter(strings.begin(), strings.end(), allLowerCase);QFuture<QSet<QString> > dictionary = QtConcurrent::filteredReduced(strings.constBegin(), strings.constEnd(), allLowerCase, addToDictionary);

2. 使用成员函数

QtConcurrent::filter()、QtConcurrent::filtered()和QtConcurrent::filteredReduced()接受指向成员函数的指针。成员函数类类型必须与序列中存储的类型匹配:

  // keep only images with an alpha channelQList<QImage> images = ...;QFuture<void> alphaImages = QtConcurrent::filter(images, &QImage::hasAlphaChannel);// retrieve gray scale imagesQList<QImage> images = ...;QFuture<QImage> grayscaleImages = QtConcurrent::filtered(images, &QImage::isGrayscale);// create a set of all printable charactersQList<QChar> characters = ...;QFuture<QSet<QChar> > set = QtConcurrent::filteredReduced(characters, &QChar::isPrint, &QSet<QChar>::insert);

注意,当使用QtConcurrent::filteredReduced()时,你可以自由地混合使用普通函数和成员函数:

  // can mix normal functions and member functions with QtConcurrent::filteredReduced()// create a dictionary of all lower cased stringsextern bool allLowerCase(const QString &string);QStringList strings = ...;QFuture<QSet<int> > averageWordLength = QtConcurrent::filteredReduced(strings, allLowerCase, QSet<QString>::insert);// create a collage of all gray scale imagesextern void addToCollage(QImage &collage, const QImage &grayscaleImage);QList<QImage> images = ...;QFuture<QImage> collage = QtConcurrent::filteredReduced(images, &QImage::isGrayscale, addToCollage);

3. 使用函数对象

QtConcurrent::filter()、QtConcurrent::filtered()和QtConcurrent::filteredReduced()接受过滤函数的函数对象。这些函数对象可用于向函数调用添加状态。result_type typepedef必须定义函数调用操作符的结果类型:

  struct StartsWith{StartsWith(const QString &string): m_string(string) { }typedef bool result_type;bool operator()(const QString &testString){return testString.startsWith(m_string);}QString m_string;};QList<QString> strings = ...;QFuture<QString> fooString = QtConcurrent::filtered(strings, StartsWith(QLatin1String("Foo")));

对于reduce函数,不直接支持函数对象。但是,当显式指定了缩减结果的类型时,可以使用函数对象:

  struct StringTransform{void operator()(QString &result, const QString &value);};QFuture<QString> fooString =QtConcurrent::filteredReduced<QString>(strings,StartsWith(QLatin1String("Foo")),StringTransform());

4. 包装接受多个参数的函数

如果您想使用接受多个参数的过滤器函数,可以使用lambda函数或std::bind()将其转换为接受一个参数的函数。
作为一个例子,我们使用QString::contains():

bool QString::contains(const QRegularExpression &regexp) const;

QString::contains()接受2个参数(包括“this”指针),不能直接与QtConcurrent::filtered()一起使用,因为QtConcurrent::filtered()期望一个函数接受一个参数。要将QString::contains()与QtConcurrent::filtered()一起使用,我们必须为regexp参数提供一个值:

  QStringList strings = ...;QFuture<QString> future = QtConcurrent::filtered(list, [](const QString &str) {return str.contains(QRegularExpression("^\\S+$")); // matches strings without whitespace});

四、Concurrent Run

QtConcurrent::run()函数在一个单独的线程中运行一个函数。函数的返回值可以通过QFuture API获得。

这个函数是Qt Concurrent框架的一部分。

1. 在单独的线程中运行函数

要在另一个线程中运行一个函数,使用QtConcurrent::run():

  extern void aFunction();QFuture<void> future = QtConcurrent::run(aFunction);

这将在从默认QThreadPool获得的单独线程中运行function。您可以使用QFuture和QFutureWatcher类来监视函数的状态。

要使用专用线程池,你可以将QThreadPool作为第一个参数:

  extern void aFunction();QThreadPool pool;QFuture<void> future = QtConcurrent::run(&pool, aFunction);

2. 向函数传递参数

向函数传递参数是通过将参数添加到函数名后面的QtConcurrent::run()调用中来完成的。例如:

  extern void aFunctionWithArguments(int arg1, double arg2, const QString &string);int integer = ...;double floatingPoint = ...;QString string = ...;QFuture<void> future = QtConcurrent::run(aFunctionWithArguments, integer, floatingPoint, string);

在调用QtConcurrent::run()时生成每个参数的副本,并在线程开始执行函数时将这些值传递给线程。

调用QtConcurrent::run()后对参数所做的更改对线程是不可见的。

3. 从函数返回值

函数的任何返回值都可以通过QFuture获得:

  extern QString functionReturningAString();QFuture<QString> future = QtConcurrent::run(functionReturningAString);...QString result = future.result();

如上所述,传递参数是这样做的:

  extern QString someFunction(const QByteArray &input);QByteArray bytearray = ...;QFuture<QString> future = QtConcurrent::run(someFunction, bytearray);...QString result = future.result();

注意,QFuture::result()函数阻塞并等待结果可用。当函数完成执行并且结果可用时,使用QFutureWatcher获取通知。

4. 其他API特性

1. 使用成员函数

QtConcurrent::run()也接受成员函数的指针。第一个实参必须是const引用或指向类实例的指针。在调用const成员函数时,通过const引用传递是有用的;指针传递对于调用修改实例的非const成员函数很有用。

例如,在单独的线程中调用QByteArray::split()(一个const成员函数)是这样做的:

  // call 'QList<QByteArray>  QByteArray::split(char sep) const' in a separate threadQByteArray bytearray = "hello world";QFuture<QList<QByteArray> > future = QtConcurrent::run(bytearray, &QByteArray::split, ',');...QList<QByteArray> result = future.result();

调用非const成员函数是这样做的:

  // call 'void QImage::invertPixels(InvertMode mode)' in a separate threadQImage image = ...;QFuture<void> future = QtConcurrent::run(&image, &QImage::invertPixels, QImage::InvertRgba);...future.waitForFinished();// At this point, the pixels in 'image' have been inverted

2. 使用Lambda函数

调用lambda函数是这样做的:

  QFuture<void> future = QtConcurrent::run([=]() {// Code in this block will run in another thread});...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/116817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis TypeHandler 介绍及使用

Mybatis TypeHandler类型转换器是负责Java类和jdbc类型之间的转换 主要涉及到下面这几个类&#xff1a; TypeHandler 类型转换器的顶层接口BaseTypeHandler 抽象类继承自TypeHandler&#xff0c;Mybatis中所有的类型转换器实现均继承他。TypeHandlerRegistry 类型转换器注册器…

制药企业固体制剂设备管理及维护要点

在制药企业的生产过程中&#xff0c;固体制剂设备是至关重要的一环。有效管理和维护这些设备对于确保生产质量、提高生产效率以及延长设备寿命至关重要。本文将从以下三个方面介绍制药企业固体制剂设备的主要类型、常见管理问题以及设备维护的关键要点。 制药企业固体制剂设备主…

java智慧工地云平台源码,以物联网、移动互联网技术为基础,结合大数据、云计算等,实现工程管理绿色化、数字化、精细化、智能化的效果

智慧工地将更多人工智能、传感技术、虚拟现实等高科技技术植入到建筑、机械、人员穿戴设施、场地进出关口等各类物体中&#xff0c;围绕人、机、料、法、环等各方面关键因素&#xff0c;彻底改变传统建筑施工现场参建各方现场管理的交互方式、工作方式和管理模式&#xff0c;智…

WPF 设置全局静态参数

可以使用system官方库来设置参数 引入system xmlns:system"clr-namespace:System;assemblymscorlib"设置参数资源 <Window.Resources><system:Double x:Key"ButtonWidth">90</system:Double></Window.Resources>使用参数资源 &l…

分析概览 文章管理 草稿管理 图片管理 站点管理 主站 关于 登出 手写操作系统项目----进程

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家来访。 这里记录了&#xff0c;手写操作系统项目中关于进程的部分。 进程四要素 首先进程有四要素。 …

Linux软件包和进程管理

一、RPM软件包管理 1、RPM管理工具 &#xff08;1&#xff09;RPM是红帽包管理(Redhat Package Manager)的缩写。 由Red Hat公司提出的一种软件包管理标准。 是Linux各发行版中应用最广泛的软件包格式之一&#xff08;还有debian的发行版deb安装包&#xff09;。 RPM功能通过…

数据结构:选择题+编程题(每日一练)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;单值二叉树 思路一&#xff1a; 题二&#xff1a;二叉树的最大深度 思路一&#xff1a; 本人实力有限可能对…

MySQL的索引——索引的介绍及其数据结构B+树 索引的类型 索引的使用及其失效场景 相关名词解释

前言 索引是存储引擎用于快速查找数据纪录的一种数据结构&#xff0c;索引是数据库中经常提及的一个词&#xff0c;究竟什么是索引&#xff0c;索引的数据结构是什么&#xff0c;索引有什么类型&#xff1f; 本篇博客尝试阐述数据库索引的相关内容&#xff0c;涉及什么是索引…

用 Java 在 PDF 中创建和管理图层,实现交互式文档

PDF 图层&#xff08;也称为可见图层或附加图层等&#xff09;是组织和管理 PDF 文档中内容可见性的一种方法。PDF 图层可用于创建交互式文档、隐藏或显示特定信息、创建多语言版本文档等。通过添加和删除图层&#xff0c;用户可以根据需要定制 PDF 文档指定内容的可见性与显示…

适用于物联网的UI设计工具都有哪些?

随着科学技术的飞速发展&#xff0c;“万物相连的互联网”时代逐渐成为现实。如今&#xff0c;物联网已经不是什么新词了。事实上&#xff0c;早在各种屏幕设备诞生之前&#xff0c;人们就与物理世界交织在一起&#xff0c;产生了无数的互动。如何将人们多年积累的互动经验与物…

Ubuntu下载工具ip addr、ifconfig、ping、make

Ubuntu下载工具ip addr、ifconfig、ping、make ping 在 Ubuntu 上获取网络工具包通常是通过安装相关软件包的方式来完成的。Ubuntu 默认包含一些常见的网络工具&#xff0c;但如果你需要安装其他工具&#xff0c;你可以使用 apt 命令或者 snap 命令进行安装。以下是一些常见的…

蓝桥杯 Java 青蛙过河

import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改/**二分法从大&#xff08;n&#xff09;到小找足够小的步长前缀和记录每个位置的前面有的总石头数&#xff08;一个石头表示可以容纳一个青蛙&#xff0c;一位置有多少个石头hi就是多少&#xff09;&…

025-第三代软件开发-实现需求长时间未操作返回登录界面

第三代软件开发-实现需求长时间未操作返回登录界面 文章目录 第三代软件开发-实现需求长时间未操作返回登录界面项目介绍实现需求长时间未操作返回登录界面实现思路用户操作监控QML 逻辑处理 关键字&#xff1a; Qt、 Qml、 QTimer、 timeout、 eventFilter 项目介绍 欢迎…

秋季期中考复现xj

flow analysis 1 What is the backdoor file name that comes with the server?( Including file suffix) 服务器自带的后门文件是什么&#xff1f;&#xff08;含文件后缀&#xff09; 题目还要求最后把那个文件名MD5一下&#xff0c;再去提交 开始的前三题是流量分析的&…

发挥服务器的无限潜能:创意项目、在线社区和更多

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

设计模式:观察者模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《命令模式》 下一篇《策略模式》 简介&#xff1a; 观察者模式&#xff0c;它是一种行为型设计模式&#xff0c;它允许一个对象自动通知其依赖者&#xff08;观察者&#xff09;状态的变化。当被…

Python150题day19

4.4 字符串大写转小写 在Python中&#xff0c;可以使用lower()方法将字符串中的大写字母转换为小写字母。lower()方法返回一个新的字符串&#xff0c;原始字符串本身不会被修改。 下面是一个示例&#xff1a; text "HELLO, WORLD!" lower_text text.lower() prin…

linux驱动文件私有数据(字符设备基础二)

编写linux驱动程序时&#xff0c;通常在驱动开发中会为设备定义相关的设备结构体&#xff0c;将硬件属性的描述信息全部放在该结构体中   Linux 中并没有明确规定要使用文件私有数据&#xff0c;但是在 linux 驱动源码中&#xff0c;广泛使用了文件私有数据&#xff0c;这是 …

Spring异步任务笔记

都是使用corn表达式&#xff0c;但是Spring的异步任务框架corn表达式只有6位&#xff0c;不支持第七位。周的表示&#xff1a;Spring中的corn表达式周一到周日表示为1-7&#xff0c;如Quarz则是周日到周六由1-7表示。定时任务不应该阻塞&#xff1a;&#xff08;Spring中默认是…

Non-constant range: argument must be an integer literal

更新 Xcode IDE 后 ForEach 方法抛出了如下异常 Non-constant range: argument must be an integer literal 新增了指向性 id 参数 init(_:content:) 原始方法 ForEach(0 ..< pickerTitleColors.count) {Text(self.pickerTitleColors[$0]).tag($0).foregroundColor(self.…