鄂州市 网站建设,郑州企业建站网站,福田做网站价格,建设环境工程技术中心网站Qt Concurrent概述 一、概述二、Concurrent Map 和 Map- reduce1. 并发 Map2. 并发 Map-Reduce3. 其他API特性1. 使用迭代器而不是Sequence3. 阻塞变量4. 使用成员函数5. 使用函数对象6. 包装接受多个参数的函数 三、Concurrent Filter and Filter-Reduce1. 并发过滤器2. 并发F… Qt Concurrent概述 一、概述二、Concurrent Map 和 Map- reduce1. 并发 Map2. 并发 Map-Reduce3. 其他API特性1. 使用迭代器而不是Sequence3. 阻塞变量4. 使用成员函数5. 使用函数对象6. 包装接受多个参数的函数 三、Concurrent Filter and Filter-Reduce1. 并发过滤器2. 并发Filter-Reduce3. 其他API特性1. 使用迭代器而不是Sequence2. 使用成员函数3. 使用函数对象4. 包装接受多个参数的函数 四、Concurrent Run1. 在单独的线程中运行函数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。我们可以像使用异步变量一样使用它们。 QListQImage images ...;// Each call blocks until the entire operation is finished.QListQImage 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);}QListQImage images ...;QFutureQImage 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);}QListQImage images ...;QFuturevoid future QtConcurrent::map(images, scale);由于序列被就地修改QtConcurrent::map()不会通过QFuture返回任何结果。但是我们仍然可以使用QFuture和QFutureWatcher来监视 Map 的状态。
2. 并发 Map-Reduce
QtConcurrent::mappedReduced()类似于QtConcurrent::mapped()但不是返回带有新结果的序列而是使用reduce函数将结果组合成单个值。
QFutureResultType 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 ...;}QListQImage images ...;QFutureQImage collage QtConcurrent::mappedReduced(images, scaled, addToCollage);对于map函数返回的每个结果reduce函数将被调用一次并且应该将中间值合并到result变量中。
QtConcurrent::mappedReduced() 保证一次只有一个线程调用reduce所以没有必要使用互斥锁来锁定结果变量。
ReduceOptions enum提供了一种方法来控制执行缩减的顺序。如果使用QtConcurrent::UnorderedReduce(默认值)则顺序是未定义的而QtConcurrent::OrderedReduce确保按原始序列的顺序进行缩减。
3. 其他API特性
1. 使用迭代器而不是Sequence
以上每个函数都有一个变体它接受迭代器范围而不是序列。使用它们的方式与序列变体相同:
QListQImage images ...;QFutureQImage thumbnails QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);// Map in-place only works on non-const iterators.
QFuturevoid future QtConcurrent::map(images.begin(), images.end(), scale);QFutureQImage collage QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);3. 阻塞变量
上面的每个函数都有一个阻塞变量它返回最终结果而不是QFuture。我们可以像使用异步变量一样使用它们。 QListQImage images ...;// Each call blocks until the entire operation is finished.QListQImage 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 ...;QFuturevoid squeezedStrings QtConcurrent::map(strings, QString::squeeze);// Swap the rgb values of all pixels on a list of images.QListQImage images ...;QFutureQImage bgrImages QtConcurrent::mapped(images, QImage::rgbSwapped);// Create a set of the lengths of all strings in a list.QStringList strings ...;QFutureQSetint wordLengths QtConcurrent::mappedReduced(strings, QString::length, QSetint::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 ...;QFutureint 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);QListQImage images ...;QFutureQSetint totalColorDistribution QtConcurrent::mappedReduced(images, colorDistribution, QSetint::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;};QListQImage images ...;QFutureQImage thumbnails QtConcurrent::mapped(images, Scaled(100));对于reduce函数不直接支持函数对象。但是当显式指定了缩减结果的类型时可以使用函数对象: struct ImageTransform{void operator()(QImage result, const QImage value);};QFutureQImage thumbNails QtConcurrent::mappedReducedQImage(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()我们必须提供一个宽度和转换模式的值: QListQImage images ...;std::functionQImage(const QImage ) scale [](const QImage img) {return img.scaledToWidth(100, Qt::SmoothTransformation);};QFutureQImage 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);QSetQString 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 ...;QFutureQString lowerCaseStrings QtConcurrent::filtered(strings, allLowerCase);过滤器的结果可以通过QFuture获得。有关如何在应用程序中使用QFuture的更多信息请参阅QFuture和QFutureWatcher文档。
如果你想就地修改一个序列使用QtConcurrent::filter(): QStringList strings ...;QFuturevoid 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(QSetQString dictionary, const QString string){dictionary.insert(string);}QStringList strings ...;QFutureQSetQString dictionary QtConcurrent::filteredReduced(strings, allLowerCase, addToDictionary);对于过滤器函数保存的每个结果reduce函数将被调用一次并且应该将中间结果合并到结果变量中。
QtConcurrent::filteredReduced()保证一次只有一个线程调用reduce所以没有必要使用互斥锁来锁定结果变量。ReduceOptions enum提供了一种方法来控制执行缩减的顺序。
3. 其他API特性
1. 使用迭代器而不是Sequence
以上每个函数都有一个变体它接受迭代器范围而不是序列。使用它们的方式与序列变体相同: QStringList strings ...;QFutureQString lowerCaseStrings QtConcurrent::filtered(strings.constBegin(), strings.constEnd(), allLowerCase);// filter in-place only works on non-const iteratorsQFuturevoid future QtConcurrent::filter(strings.begin(), strings.end(), allLowerCase);QFutureQSetQString dictionary QtConcurrent::filteredReduced(strings.constBegin(), strings.constEnd(), allLowerCase, addToDictionary);2. 使用成员函数
QtConcurrent::filter()、QtConcurrent::filtered()和QtConcurrent::filteredReduced()接受指向成员函数的指针。成员函数类类型必须与序列中存储的类型匹配: // keep only images with an alpha channelQListQImage images ...;QFuturevoid alphaImages QtConcurrent::filter(images, QImage::hasAlphaChannel);// retrieve gray scale imagesQListQImage images ...;QFutureQImage grayscaleImages QtConcurrent::filtered(images, QImage::isGrayscale);// create a set of all printable charactersQListQChar characters ...;QFutureQSetQChar set QtConcurrent::filteredReduced(characters, QChar::isPrint, QSetQChar::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 ...;QFutureQSetint averageWordLength QtConcurrent::filteredReduced(strings, allLowerCase, QSetQString::insert);// create a collage of all gray scale imagesextern void addToCollage(QImage collage, const QImage grayscaleImage);QListQImage images ...;QFutureQImage 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;};QListQString strings ...;QFutureQString fooString QtConcurrent::filtered(strings, StartsWith(QLatin1String(Foo)));对于reduce函数不直接支持函数对象。但是当显式指定了缩减结果的类型时可以使用函数对象: struct StringTransform{void operator()(QString result, const QString value);};QFutureQString fooString QtConcurrent::filteredReducedQString(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 ...;QFutureQString 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();QFuturevoid future QtConcurrent::run(aFunction);这将在从默认QThreadPool获得的单独线程中运行function。您可以使用QFuture和QFutureWatcher类来监视函数的状态。
要使用专用线程池你可以将QThreadPool作为第一个参数: extern void aFunction();QThreadPool pool;QFuturevoid future QtConcurrent::run(pool, aFunction);2. 向函数传递参数
向函数传递参数是通过将参数添加到函数名后面的QtConcurrent::run()调用中来完成的。例如: extern void aFunctionWithArguments(int arg1, double arg2, const QString string);int integer ...;double floatingPoint ...;QString string ...;QFuturevoid future QtConcurrent::run(aFunctionWithArguments, integer, floatingPoint, string);在调用QtConcurrent::run()时生成每个参数的副本并在线程开始执行函数时将这些值传递给线程。
调用QtConcurrent::run()后对参数所做的更改对线程是不可见的。
3. 从函数返回值
函数的任何返回值都可以通过QFuture获得: extern QString functionReturningAString();QFutureQString future QtConcurrent::run(functionReturningAString);...QString result future.result();如上所述传递参数是这样做的: extern QString someFunction(const QByteArray input);QByteArray bytearray ...;QFutureQString 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 QListQByteArray QByteArray::split(char sep) const in a separate threadQByteArray bytearray hello world;QFutureQListQByteArray future QtConcurrent::run(bytearray, QByteArray::split, ,);...QListQByteArray result future.result();调用非const成员函数是这样做的: // call void QImage::invertPixels(InvertMode mode) in a separate threadQImage image ...;QFuturevoid future QtConcurrent::run(image, QImage::invertPixels, QImage::InvertRgba);...future.waitForFinished();// At this point, the pixels in image have been inverted2. 使用Lambda函数
调用lambda函数是这样做的: QFuturevoid future QtConcurrent::run([]() {// Code in this block will run in another thread});...
文章转载自: http://www.morning.qyxwy.cn.gov.cn.qyxwy.cn http://www.morning.qnrpj.cn.gov.cn.qnrpj.cn http://www.morning.dhxnr.cn.gov.cn.dhxnr.cn http://www.morning.mggwr.cn.gov.cn.mggwr.cn http://www.morning.hnmbq.cn.gov.cn.hnmbq.cn http://www.morning.bzbq.cn.gov.cn.bzbq.cn http://www.morning.xwgbr.cn.gov.cn.xwgbr.cn http://www.morning.cflxx.cn.gov.cn.cflxx.cn http://www.morning.wpcfm.cn.gov.cn.wpcfm.cn http://www.morning.zjcmr.cn.gov.cn.zjcmr.cn http://www.morning.hhxkl.cn.gov.cn.hhxkl.cn http://www.morning.nmfxs.cn.gov.cn.nmfxs.cn http://www.morning.wrtbx.cn.gov.cn.wrtbx.cn http://www.morning.mqmmc.cn.gov.cn.mqmmc.cn http://www.morning.cnhgc.cn.gov.cn.cnhgc.cn http://www.morning.jtmql.cn.gov.cn.jtmql.cn http://www.morning.frpb.cn.gov.cn.frpb.cn http://www.morning.ngcw.cn.gov.cn.ngcw.cn http://www.morning.fmry.cn.gov.cn.fmry.cn http://www.morning.ywtbk.cn.gov.cn.ywtbk.cn http://www.morning.xhlht.cn.gov.cn.xhlht.cn http://www.morning.yxshp.cn.gov.cn.yxshp.cn http://www.morning.gqfks.cn.gov.cn.gqfks.cn http://www.morning.gkgr.cn.gov.cn.gkgr.cn http://www.morning.tgcw.cn.gov.cn.tgcw.cn http://www.morning.xwbld.cn.gov.cn.xwbld.cn http://www.morning.hwxxh.cn.gov.cn.hwxxh.cn http://www.morning.ljzgf.cn.gov.cn.ljzgf.cn http://www.morning.rwjh.cn.gov.cn.rwjh.cn http://www.morning.dnmwl.cn.gov.cn.dnmwl.cn http://www.morning.xqspn.cn.gov.cn.xqspn.cn http://www.morning.bpmfq.cn.gov.cn.bpmfq.cn http://www.morning.wkmrl.cn.gov.cn.wkmrl.cn http://www.morning.ksgjn.cn.gov.cn.ksgjn.cn http://www.morning.jrqw.cn.gov.cn.jrqw.cn http://www.morning.lssfd.cn.gov.cn.lssfd.cn http://www.morning.rqjxc.cn.gov.cn.rqjxc.cn http://www.morning.kzcfp.cn.gov.cn.kzcfp.cn http://www.morning.zlchy.cn.gov.cn.zlchy.cn http://www.morning.msbpb.cn.gov.cn.msbpb.cn http://www.morning.nswcw.cn.gov.cn.nswcw.cn http://www.morning.qwdlj.cn.gov.cn.qwdlj.cn http://www.morning.wqrdx.cn.gov.cn.wqrdx.cn http://www.morning.ltcnd.cn.gov.cn.ltcnd.cn http://www.morning.ghwtn.cn.gov.cn.ghwtn.cn http://www.morning.wrkcw.cn.gov.cn.wrkcw.cn http://www.morning.wmrgp.cn.gov.cn.wmrgp.cn http://www.morning.cgmzt.cn.gov.cn.cgmzt.cn http://www.morning.hmgqy.cn.gov.cn.hmgqy.cn http://www.morning.xswrb.cn.gov.cn.xswrb.cn http://www.morning.jnbsx.cn.gov.cn.jnbsx.cn http://www.morning.pdtjj.cn.gov.cn.pdtjj.cn http://www.morning.lyhrg.cn.gov.cn.lyhrg.cn http://www.morning.jfcbz.cn.gov.cn.jfcbz.cn http://www.morning.hjjhjhj.com.gov.cn.hjjhjhj.com http://www.morning.gkdqt.cn.gov.cn.gkdqt.cn http://www.morning.fbjnr.cn.gov.cn.fbjnr.cn http://www.morning.zcrjq.cn.gov.cn.zcrjq.cn http://www.morning.hqllx.cn.gov.cn.hqllx.cn http://www.morning.jlmrx.cn.gov.cn.jlmrx.cn http://www.morning.lqrpk.cn.gov.cn.lqrpk.cn http://www.morning.nkmw.cn.gov.cn.nkmw.cn http://www.morning.yrcxg.cn.gov.cn.yrcxg.cn http://www.morning.gynlc.cn.gov.cn.gynlc.cn http://www.morning.fhsgw.cn.gov.cn.fhsgw.cn http://www.morning.hjlwt.cn.gov.cn.hjlwt.cn http://www.morning.wtbzt.cn.gov.cn.wtbzt.cn http://www.morning.glswq.cn.gov.cn.glswq.cn http://www.morning.ldnrf.cn.gov.cn.ldnrf.cn http://www.morning.fylqz.cn.gov.cn.fylqz.cn http://www.morning.thrcj.cn.gov.cn.thrcj.cn http://www.morning.bhrbr.cn.gov.cn.bhrbr.cn http://www.morning.zwwhq.cn.gov.cn.zwwhq.cn http://www.morning.jwskq.cn.gov.cn.jwskq.cn http://www.morning.mzwqt.cn.gov.cn.mzwqt.cn http://www.morning.qlznd.cn.gov.cn.qlznd.cn http://www.morning.ljzqb.cn.gov.cn.ljzqb.cn http://www.morning.fqsxf.cn.gov.cn.fqsxf.cn http://www.morning.xmttd.cn.gov.cn.xmttd.cn http://www.morning.sdktr.com.gov.cn.sdktr.com