GVKun编程网logo

终端/ zsh / terminfo中的应用模式是什么?(终端terminal)

13

在本文中,我们将为您详细介绍终端/zsh/terminfo中的应用模式是什么?的相关知识,并且为您解答关于终端terminal的疑问,此外,我们还会提供一些关于C#中的资源释放模式是什么?、ccflo

在本文中,我们将为您详细介绍终端/ zsh / terminfo中的应用模式是什么?的相关知识,并且为您解答关于终端terminal的疑问,此外,我们还会提供一些关于C#中的资源释放模式是什么?、ccflow 在基于最新版本的实现原理是什么?涉及的架构模式是什么?、CM模式是什么?如何应用?、Flink 中的应用部署:当前状态与新应用模式的有用信息。

本文目录一览:

终端/ zsh / terminfo中的应用模式是什么?(终端terminal)

终端/ zsh / terminfo中的应用模式是什么?(终端terminal)

在 several places中,我看到一些命令以确保终端(?)处于应用程序模式,然后terminfo数据库设置/查询键绑定将起作用.

我试图找到这种应用模式是什么,但我没有成功.这个应用模式是什么?我认为没有它,Zsh可以正常运行.我对吗?在处理密钥绑定后,是否需要取消设置?一些应用程序会不会像基于curses的应用程序那样解决它?

这只是一个问题:“什么是应用程序模式或它是如何工作的”.我写了其他问题只是为了帮助你理解我的问题.

解决方法

如果有人遇到同样的问题……经过一些研究,我在 one prezto’s pull request下找到了我的问题的答案.

它可以总结如下:

>终端未指定且非通用.有几种不同的协议来处理移动光标,更改颜色和处理用户的键组合输入的扩展.
>有人创建了一个大型数据库来抽象不同终端和终端模拟器之间的差异.该数据库是terminfo.
> terminfo仅适用于应用程序模式.特殊的转义序列被发送到终端,然后它可以改变它的模式.在新模式中,它将接受不同的转义序列(terminfo已知的转义序列).
>可以检测是否支持应用程序模式,如果没有,则可以回退到其他方法(zkbd,…).
> zsh的常用配置设置zle(zsh的行编辑器)在接收用户输入之前进入应用程序模式并在执行任何命令之前退出.然后所有应用程序将继续正常运行.

注意:并非所有常见的zsh配置都非常强大,建议您阅读前面提到的prezto’s pull request.

我的配置位记录于my blog,可在my git repo获得.

C#中的资源释放模式是什么?

C#中的资源释放模式是什么?

c#的dispose模式是什么

C#的Dispose模式是一种用于释放和清理非托管资源的模式。在C#中,垃圾回收器会自动回收托管资源,但对于非托管资源(如文件、数据库连接、网络连接等),则需要手动进行释放和清理。Dispose模式提供了一种标准的方式来确保这些非托管资源在不再被使用时能够被及时释放和清理,以避免资源泄漏和性能问题。

使用Dispose模式的类通常实现了IDisposable接口,这个接口定义了一个Dispose方法,该方法用于释放非托管资源。该方法可以在类的实例被销毁之前手动调用,也可以通过using语句块自动调用。使用using语句块可以确保在代码块执行完毕后,被使用的资源能够被及时释放和清理。

下面是一个示例代码,演示了如何使用Dispose模式释放文件资源:

using System;
using System.IO;

public class FileResource : IDisposable
{
    private FileStream _fileStream;

    public FileResource(string filePath)
    {
        _fileStream = new FileStream(filePath, FileMode.Open);
    }

    public void ReadFile()
    {
        byte[] buffer = new byte[10];
        _fileStream.Read(buffer, 0, buffer.Length);
        Console.WriteLine(Encoding.UTF8.GetString(buffer));
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_fileStream != null)
            {
                _fileStream.Dispose(); // 释放文件流资源
                _fileStream = null;
            }
        }
    }
}

public class Program
{
    public static void Main()
    {
        using (FileResource resource = new FileResource("sample.txt"))
        {
            resource.ReadFile();
        }
    }
}
登录后复制

在这个例子中,我们创建了一个FileResource类,它在构造函数中打开了一个文件流,并在ReadFile方法中读取文件内容并打印出来。在Dispose方法中,我们调用了_fileStream的Dispose方法来释放文件流资源,并将_fileStream置为null。

在Main方法中,我们使用using语句块创建了一个FileResource实例,当代码块执行完毕时,using语句块会自动调用FileResource的Dispose方法,以释放文件流资源。

Dispose模式确保了非托管资源的及时释放和清理,有效地提高了代码的可维护性和性能。在开发C#应用程序时,如果使用了非托管资源,建议使用Dispose模式来管理这些资源的生命周期。

以上就是C#中的资源释放模式是什么?的详细内容,更多请关注php中文网其它相关文章!

ccflow 在基于最新版本的实现原理是什么?涉及的架构模式是什么?

ccflow 在基于最新版本的实现原理是什么?涉及的架构模式是什么?

package BP.DA;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import BP.Tools.StringHelper;

public class DataSet {

   private String name;

   public List<DataTable> Tables;

   public Hashtable<String, DataTable> hashTables;

// private XmlWriteMode xmlWriteMode = XmlWriteMode.IgnoreSchema;

   public DataSet() {
      if (Tables == null) {
         Tables = new ArrayList<DataTable>();
         hashTables = new Hashtable<String, DataTable>();
      }
   }
   
   public boolean removeTableByName(String tableName)
   {
      
      for (DataTable dtb : this.Tables)
         {
            if( tableName.equals(dtb.getTableName()))
            {
               this.Tables.remove(dtb);
               return true;
                      
            }
         }  
      
      return false;
       
   }
   
   public DataTable GetTableByName(String tableName)
   {
      
      for (DataTable dtb : this.Tables)
         {
            if( tableName.equals(dtb.getTableName()))
            {
               return dtb;
             
            }
         }  
      
      return null;
      
   }

   public DataSet(String name) {
      if (Tables == null) {
         Tables = new ArrayList<DataTable>();
         hashTables = new Hashtable<String, DataTable>();
      }
      this.name = name;
   }

   /**
    * DataSet 以xml形式写入文件
    * 
    * @param file
    */
   public void WriteXml(String file) {
      WriteXml(file, XmlWriteMode.IgnoreSchema, new DataSet("NewDataSet"));
   }

   /**
    * DataSet 以xml形式写入文件
    * 
    * @param path
    * @param mode
    *            暂不支持DiffGram格式
    * @throws Exception
    */
   public void WriteXml(String path, XmlWriteMode mode, DataSet ds) {
      StringBuilder str = new StringBuilder("<?xml version=\"1.0\" standalone=\"yes\"?>");
      str.append("<NewDataSet>");
      // 输出表架构
      for (int i = 0; i < ds.Tables.size(); i++) {
         DataTable dt = ds.Tables.get(i);
         for (int k = 0; k < dt.Rows.size(); k++) {
            str.append("<");
            str.append(dt.TableName);
            str.append(">");
            for (int j = 0; j < dt.Columns.size(); j++) {
               DataColumn dc = dt.Columns.get(j);

               str.append("<");
               str.append(dc.ColumnName);
               str.append(">");
               try {
                  Object value = dt.Rows.get(k).getValue(dc);
                  if (value.toString().contains(">") || value.toString().contains("<") || value.toString().contains("&")
                        || value.toString().contains("''") || value.toString().contains("\"")) {
                     value = value.toString().replace(">", "&gt;");
                     value = value.toString().replace("<", "&lt;");
                     value = value.toString().replace("&", "&amp;");
                     value = value.toString().replace("''", "&apos;");
                     value = value.toString().replace("\"", "&quot;");
                  }
                  str.append(value);
               } catch (Exception e) {

               }
               str.append("</");
               str.append(dc.ColumnName);
               str.append(">");

            }
            str.append("</");
            str.append(dt.TableName);
            str.append(">");
         }
      }
      // }
      str.append("</NewDataSet>");
      String temp = str.toString();
      // String temp = formatXml(str.toString());

      // 写入文件
      File file = new File(path);
      try {
         if (!file.exists()) {
            file.createNewFile();
         }
         FileOutputStream fos = new FileOutputStream(file);
         OutputStreamWriter osw = new OutputStreamWriter(fos, "utf-8");
         BufferedWriter br = new BufferedWriter(osw);
         br.write(temp.toString());
         fos.flush();
         br.close();
         fos.close();
         osw.close();

      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   public String formatXml(String str) throws Exception {
      Document document = null;
      document = DocumentHelper.parseText(str);
      // 格式化输出格式
      OutputFormat format = OutputFormat.createPrettyPrint();
      format.setEncoding("gbk");
      StringWriter writer = new StringWriter();
      // 格式化输出流
      XMLWriter xmlWriter = new XMLWriter(writer, format);
      // 将document写入到输出流
      xmlWriter.write(document);
      xmlWriter.close();

      return writer.toString();
   }

   public void readXmls(String xmlPath) throws Exception {
      if (StringHelper.isNullOrEmpty(xmlPath)) {
         return;
      }

//    XMLWriter writer = null;// 声明写XML的对象
      SAXReader reader = new SAXReader();

      File file = new File(xmlPath);
      // DataSet ds=new DataSet();
      if (file.exists()) {
         Document document = reader.read(file);// 读取XML文件
         Element root = document.getRootElement();// 得到根节点
         for (Iterator i = root.elementIterator(); i.hasNext();) {
            Element e = (Element) i.next();
            boolean type = false;
            for (int k = 0; k < this.Tables.size(); k++) {
               if (this.Tables.get(k).TableName.equals(e.getName())) {
                  DataTable dt = this.Tables.get(k);
                  DataRow dr = dt.NewRow();
                  DataColumn dc = null;
                  for (Iterator j = e.elementIterator(); j.hasNext();) {
                     Element cn = (Element) j.next();
                     dc = new DataColumn(cn.getName());
                     dr.setValue(dc, cn.getText());
                  }
                  dt.Columns.Add(dc);
                  dt.Rows.add(dr);
                  // this.Tables.add(dt);
                  // this.hashTables.put(e.getName(), dt);
                  type = true;
                  break;
               }
            }
            if (type) {
               continue;
            }
            DataTable dt = new DataTable(e.getName());
            DataRow dr = dt.NewRow();
            DataColumn dc = null;
            for (Iterator j = e.elementIterator(); j.hasNext();) {
               Element cn = (Element) j.next();
               dc = new DataColumn(cn.getName());
               dt.Columns.Add(dc);
               dr.setValue(dc, cn.getText());
            }
            dt.Rows.add(dr);
            this.Tables.add(dt);
            this.hashTables.put(e.getName(), dt);
         }
      }
   }

   public void readXmlm(String xml) {
      if (StringHelper.isNullOrEmpty(xml))
         return;
      try {
         xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\r\n <NewDataSets>" + xml + "</NewDataSets>";
         // 创建xml解析对象
         SAXReader reader = new SAXReader();
         // 定义一个文档
         Document document = null;
         // 将字符串转换为
         document = reader.read(new ByteArrayInputStream(xml.getBytes("UTF-8")));
         @SuppressWarnings("unchecked")
         List<Element> elements = document.selectNodes("//NewDataSets/NewDataSet");

         int i = 0;
         DataTable oratb = new DataTable();
         for (Element element : elements) {
            DataRow dr = oratb.NewRow();
            @SuppressWarnings("unchecked")
            Iterator<Element> iter = element.elementIterator();
            int j = 0;
            while (iter.hasNext()) {
               Element itemEle = (Element) iter.next();
               if (i == 0) {
                  oratb.Columns.Add(itemEle.getName());
               }
               dr.setValue(j, itemEle.getTextTrim());
               j++;
            }
            oratb.Rows.add(dr);
            i++;
         }
         this.Tables.add(oratb);
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public List<DataTable> getTables() {
      return Tables;
   }

   public void setTables(List<DataTable> tables) {
      Tables = tables;
   }

   public Hashtable<String, DataTable> getHashTabless() {
      return hashTables;
   }

   public void setHashTables(Hashtable<String, DataTable> hashTables) {
      this.hashTables = hashTables;
   }

   /**
    * 获取文件的XML文件内容。
    * @param path xml文件路径
    * @return xml文件内容
    */
   public String xmlToString(String path) {
      String line = null;
      StringBuffer strBuffer = new StringBuffer();
      try {
         String encoding = "UTF-8"; // 字符编码(可解决中文乱码问题 )
         File file = new File(path);
         if (file.isFile() && file.exists()) {
            InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding);
            BufferedReader bufferedReader = new BufferedReader(read);
            while ((line = bufferedReader.readLine()) != null) {
               strBuffer.append(line + "\n");
            }
            read.close();
         } else {
            Log.DefaultLogWriteLineDebug("找不到指定的文件!" + path);
         }
      } catch (Exception e) {
         Log.DefaultLogWriteLineDebug("读取文件内容操作出错!" + e.getMessage());
      }
      return strBuffer.toString();
   }

   /**
    * 读取XML文件
    * @param xmlpath xml文件路径
    * @author ThinkGem
    */
   @SuppressWarnings("rawtypes")
   public void readXml(String xmlpath) {
      if (StringHelper.isNullOrEmpty(xmlpath)){
         return;
      }
      try {
         String xml = xmlToString(xmlpath);
         Document document = new SAXReader().read(new ByteArrayInputStream(xml.getBytes("UTF-8")));
         Element element = document.getRootElement();
         
         // 遍历 DataTable
         for (Iterator iterator = element.elementIterator(); iterator.hasNext();) {
            Element el = (Element) iterator.next();
//          Log.DefaultLogWriteLineDebug(" ===================== " + el.getName());
            
            // 如果没有获取到DataTable则新建一个
            DataTable dt = hashTables.get(el.getName());
            if (dt == null){
               dt = new DataTable(el.getName());
               hashTables.put(el.getName(), dt);
               Tables.add(dt);
            }
            
            // 新增一行数据
            DataRow dr = dt.NewRow();
            dt.Rows.add(dr);

            // 遍历该DataTable的属性
            for (Iterator it = el.attributeIterator(); it.hasNext();) {
               Attribute at = (Attribute)it.next();
//             Log.DefaultLogWriteLineDebug(" ======= " + at.getName());
               //sunxd 修改
               //由于"at.getName().toLowerCase()"语句导至  isContains 方法判断永远不成立,会给TABLE插入很多重复列
               //将at.getName().toLowerCase() 修改为  at.getName()
               if (!isContains(dt.Columns.subList(0, dt.Columns.size()), at.getName())) {
                  dt.Columns.Add(at.getName());
               }
               dr.setValue(at.getName(), at.getValue());
            }
            
            // 遍历该DataTable的子元素
            for (Iterator it = el.elementIterator(); it.hasNext();) {
               Element at = (Element) it.next();
//             Log.DefaultLogWriteLineDebug(" ======= " + at.getName());
               //sunxd 修改
               //由于"at.getName().toLowerCase()"语句导至  isContains 方法判断永远不成立,会给TABLE插入很多重复列
               //将at.getName().toLowerCase() 修改为  at.getName()
               if (!isContains(dt.Columns.subList(0, dt.Columns.size()), at.getName())) {
                  dt.Columns.Add(at.getName());
               }
               String value = at.getText();
               try {
                  //导出模板进行了转义,现在进行反转 dgq 2018-7-5
                  if (value.toString().contains("&gt;") || value.toString().contains("&lt;") 
                        || value.toString().contains("&amp;") || value.toString().contains("&apos;") 
                        || value.toString().contains("&quot;")) {
                     value = value.toString().replace("&amp;", "&");
                     value = value.toString().replace("&gt;",">");
                     value = value.toString().replace("&lt;","<");
                     value = value.toString().replace("&apos;","''");
                     value = value.toString().replace("&quot;","\"");
                  }
               } catch (Exception e) {

               }
               dr.setValue(at.getName(), value);
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   public boolean isContains(List<DataColumn> dcList, String column) {
      for (DataColumn dc : dcList) {
         if (dc.ColumnName.equals(column)) {
            return true;
         }
      }
      return false;
   }

   public static String ConvertDataSetToXml(DataSet dataSet) {
      if (dataSet != null) {
         String str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
         str += "<xs:schema id=\"NewDataSet\" xmlns=\"\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\">";

         str += "<xs:element name=\"NewDataSet\" msdata:IsDataSet=\"true\" msdata:UseCurrentLocale=\"true\">";
         str += "<xs:complexType><xs:choice minOccurs=\"0\" maxOccurs=\"unbounded\">";
         // 循环每一个表的列

         for (int n = 0; n < dataSet.getTables().size(); n++) {
            str += "<xs:element name=\"" + dataSet.getTables().get(n).TableName + "\">";
            str += "<xs:complexType><xs:sequence>";
            DataTable table = dataSet.getTables().get(n);
            for (DataColumn col : table.Columns) {
               str += "<xs:element name=\"" + col.ColumnName;
               str += "\" type=\"";
               try {
                  col.DataType.toString();
                  str += IsType(col.DataType.toString());
               } catch (Exception e) {
                  str += "xs:string";
               }
               str += "\" minOccurs=\"0\" />";
            }
            str += "</xs:sequence></xs:complexType></xs:element>";
         }
         str += "</xs:choice></xs:complexType></xs:element><_NewDataSet>";
         for (int i = 0; i < dataSet.getTables().size(); i++) {
            DataTable dt = dataSet.getTables().get(i);
            DataTable table = dataSet.getTables().get(i);
            for (int j = 0; j < table.Rows.size(); j++) {
               str += "<_" + i + ">";
               DataRow row = table.Rows.get(j);
               for (int a = 0; a < row.columns.size(); a++) {
                  DataColumn col = table.Columns.get(a);
                  str += "<_" + a + ">";
                  if (row.getValue(col) == null) {
                     str += "";
                  } else {
                     if (col.ColumnName.equals("icon")) {
                        if (row.getValue(col).equals("")) {
                           str += "审核";
                        } else if (row.getValue(col).equals("Default")) {
                           str += "审核";
                        } else {
                           str += row.getValue(col);
                        }
                     } else {
                        str += row.getValue(col);
                     }
                  }
                  str += "</_" + a + ">";

               }
               str += "</_" + i + ">";
            }
         }
         str += "</_NewDataSet>";
         str += "</xs:schema>";
         return str;
      }
      return null;
   }

   public static String IsType(String name) {
      if (name.equals("class java.lang.Integer")) {
         name = "xs:int";
      }
      if (name.equals("class java.lang.Long")) {
         name = "xs:long";
      }
      if (name.equals("class java.lang.Float")) {
         name = "xs:float";
      }
      if (name.equals("class java.lang.Double")) {
         name = "xs:double";
      }
      if (name.equals("class java.lang.String")) {
         name = "xs:string";
      }
      if (name.equals("class java.math.BigDecimal")) {
         name = "xs:int";
      }
      return name;
   }

   // public static void main(String[] args) {
   //    DataSet set = new DataSet();
   //    String xml = "<NewDataSet><Table><DATAID>1</DATAID> <XTSJBH>1</XTSJBH><CODE>01</CODE><YYBH>000000000000000001715130000618</YYBH><ZT>1000000000</ZT>"
   //          + "<ID>94899</ID><XM>徐宁</XM><CSNY>1983-06-02T00:00:00+08:00</CSNY><JG>411302</JG><MZ>01</MZ><CJGZSJ>2007-09-01T00:00:00+08:00</CJGZSJ><JRBXTGZSJ>2007-09-01T00:00:00+08:00</JRBXTGZSJ></Table></NewDataSet>";
   //    set.readXml(xml);
   //    Log.DefaultLogWriteLineDebug("sssssssssss");
   // }

   public static void main(String[] args) throws Exception {

      // List<DataTable> tableList = new ArrayList<DataTable>();
      // DataTable table = new DataTable("Emp");
      // DataColumn col = new DataColumn("id", Integer.class);
      // DataColumn col1 = new DataColumn("name", String.class);
      // DataColumn col2 = new DataColumn("sex", String.class);
      // DataColumn col3 = new DataColumn("age", Integer.class);
      // table.Columns.Add(col);
      // table.Columns.Add(col1);
      // table.Columns.Add(col2);
      // table.Columns.Add(col3);
      // DataRow dr1 = table.NewRow();
      // dr1.setValue(col, 1);
      // dr1.setValue(col1, "付强");
      // dr1.setValue(col2, "男");
      // dr1.setValue(col3, 21);
      // DataRow dr2 = table.NewRow();
      // dr2.setValue(col, 2);
      // dr2.setValue(col1, "熊伟");
      // dr2.setValue(col2, "男");
      // dr2.setValue(col3, 21);
      // table.Rows.add(dr1);
      // table.Rows.add(dr2);
      //
      // DataTable dept = new DataTable("dept");
      // DataColumn deptName = new DataColumn("name", String.class);
      // DataColumn deptDesc = new DataColumn("desc", String.class);
      // dept.Columns.Add(deptName);
      // dept.Columns.Add(deptDesc);
      // DataRow row = dept.NewRow();
      // row.setValue(deptName, "java开发部");
      // row.setValue(deptDesc, "开发");
      // dept.Rows.add(row);
      // DataRow row1 = dept.NewRow();
      // row1.setValue(deptName, ".net开发部");
      // row1.setValue(deptDesc, "开发");
      // dept.Rows.add(row1);
      //
      // tableList.add(table);
      // tableList.add(dept);
      // set.setTables(tableList);
      // Log.DefaultLogWriteLineDebug(ConvertDataSetToXml(set));
      
      DataSet set = new DataSet();
      set.readXml("D:/JFlow/JFlow/jflow-web/src/main/webapp/WF/Data/FlowDemo/Flow/01.线性流程/表单数据copy测试案例.xml");
      DataSet set2 = new DataSet();
      set2.readXml("D:/JFlow/JFlow/jflow-web/src/main/webapp/DataUser/XML/RegularExpression.xml");
      Log.DefaultLogWriteLineDebug("main");

   }

}

CM模式是什么?如何应用?

CM模式是什么?如何应用?

CM 模式作为一种先进的项目管理模式,在建筑工程领域中发挥着越来越重要的作用。随着数字化技术的应用、绿色建筑和可持续发展的要求、集成化和一体化管理的趋势以及国际化和跨文化管理的挑战,CM 模式也将不断创新和发展,为建筑行业的发展做出更大的贡献。

一、CM 模式概述

CM(Construction Management)模式,即建设管理模式,是一种在建筑工程领域广泛应用的项目管理方法。它起源于 20 世纪 60 年代的美国,旨在为业主提供更高效、更灵活的项目管理服务。

CM 模式的核心思想是通过专业的建设管理团队,对工程项目进行全过程的规划、协调和控制。与传统的项目管理模式不同,CM 模式强调在项目的早期阶段就介入,与设计团队紧密合作,共同优化项目方案,减少项目变更,提高项目的质量和进度控制水平。

二、CM 模式的发展历程

(一)起源与初步发展

20 世纪 60 年代,美国的建筑市场面临着项目规模不断扩大、技术复杂度不断提高、业主需求日益多样化等挑战。传统的设计 - 招标 - 建造(DBB)模式在项目进度和成本控制方面逐渐暴露出不足。在这种背景下,CM 模式应运而生。最初的 CM 模式主要应用于商业建筑和工业建筑项目,通过引入专业的建设管理团队,提前参与项目规划和设计,有效地缩短了项目建设周期。

(二)成熟与推广

20 世纪 70 - 80 年代,CM 模式在实践中不断完善和成熟。建设管理团队的职责范围进一步扩大,不仅包括项目的进度和成本控制,还涵盖了质量控制、风险管理、合同管理等方面。同时,CM 模式也逐渐得到了业主和建筑行业的广泛认可,开始在更多类型的工程项目中推广应用,如住宅建筑、公共设施建设等。

(三)国际化发展

20 世纪 90 年代以来,随着全球经济一体化的加速,CM 模式也逐渐走向国际化。许多国际工程公司将 CM 模式引入到其他国家和地区的工程项目中,并根据当地的市场环境和文化背景进行了相应的调整和创新。如今,CM 模式已经成为国际建筑工程领域中一种重要的项目管理模式。

三、CM 模式的特点

(一)早期介入

CM 模式强调建设管理团队在项目的早期规划阶段就介入,与设计团队共同工作。这样可以充分发挥建设管理团队的专业经验,对项目的可行性、功能布局、施工工艺等方面进行深入分析和优化,避免在项目实施过程中出现大量的设计变更,从而节约项目成本,缩短项目建设周期。

(二)快速路径法

CM 模式采用快速路径法(Fast - Track)进行项目建设。即在设计尚未完成时,就开始进行部分工程的施工招标和施工。这样可以使项目的设计和施工并行进行,大大缩短了项目的总建设周期。例如,在建筑主体结构设计完成后,就可以开始进行室内装修工程的招标和施工,而不必等到整个项目的设计全部完成后再开始施工。

(三)专业分工与协作

CM 模式下,建设管理团队、设计团队、施工承包商等各方之间有着明确的分工和协作关系。建设管理团队负责项目的整体规划、协调和控制,设计团队负责项目的设计工作,施工承包商负责项目的施工建设。各方之间通过密切的沟通和协作,共同实现项目的目标。

(四)风险管理

CM 模式注重项目的风险管理。建设管理团队在项目的早期阶段就对项目可能面临的风险进行识别和评估,并制定相应的风险应对措施。在项目实施过程中,建设管理团队还会对风险进行动态监控和管理,及时调整风险应对策略,确保项目的顺利进行。

四、CM 模式的作用

(一)提高项目质量

由于 CM 模式下建设管理团队在项目早期就介入,能够与设计团队共同优化项目方案,选择合适的施工工艺和材料,从而提高项目的质量水平。同时,建设管理团队在项目实施过程中对施工质量进行严格的监督和管理,确保施工符合设计要求和相关标准规范。

(二)缩短项目建设周期

通过采用快速路径法,CM 模式使项目的设计和施工并行进行,有效地缩短了项目的总建设周期。这对于业主来说,可以更快地获得项目的使用价值,提高投资回报率。对于社会来说,也可以更快地满足人们对基础设施和公共服务设施的需求。

(三)降低项目成本

CM 模式下建设管理团队的早期介入和优化设计,可以避免项目实施过程中的大量设计变更,从而节约项目成本。同时,建设管理团队通过对项目进度和成本的有效控制,合理安排资源,避免资源浪费和闲置,也可以降低项目成本。

(四)增强项目管理的专业性

CM 模式下,建设管理团队由专业的项目管理人员组成,他们具有丰富的项目管理经验和专业知识。通过他们的专业管理,可以提高项目管理的水平和效率,确保项目的顺利进行。

五、CM 模式的类型定义

(一)代理型 CM 模式(Agency CM)

在代理型 CM 模式中,CM 单位作为业主的代理,按照业主的要求进行项目管理工作。CM 单位与业主签订服务合同,代表业主与设计单位、施工承包商等进行沟通和协调。CM 单位不承担项目的施工任务,只负责项目的管理和协调工作。业主与施工承包商签订施工合同,施工承包商直接对业主负责。

(二)风险型 CM 模式

(At - Risk CM)风险型 CM 模式中,CM 单位不仅负责项目的管理和协调工作,还承担项目的施工任务。CM 单位与业主签订总承包合同,对项目的质量、进度、成本等方面承担全部责任。业主只需要与 CM 单位进行沟通和协调,不需要直接管理施工承包商。

六、CM 模式的应用场景

(一)大型复杂工程项目对于大型复杂工程项目,如高层建筑、大型商业综合体、机场航站楼等,由于项目规模大、技术难度高、涉及专业多,采用传统的项目管理模式往往难以有效地控制项目进度和成本。CM 模式通过专业的建设管理团队的早期介入和协调管理,可以更好地应对项目的复杂性,提高项目的管理水平和效率。

(二)业主对项目建设周期要求较高的项目如果业主对项目建设周期有较高的要求,希望尽快获得项目的使用价值,那么 CM 模式是一个不错的选择。通过采用快速路径法,CM 模式可以大大缩短项目的建设周期,满足业主的需求。

(三)业主缺乏项目管理经验的项目对于一些缺乏项目管理经验的业主来说,自行管理工程项目可能会面临诸多困难和风险。CM 模式下,专业的建设管理团队可以为业主提供全方位的项目管理服务,帮助业主解决项目管理过程中遇到的各种问题,降低项目风险。

七、CM 模式的步骤过程

(一)项目启动阶段

业主确定项目需求和目标,选择合适的 CM 单位。CM 单位与业主签订服务合同,明确双方的权利和义务。CM 单位组建项目管理团队,制定项目管理计划。

(二)项目规划阶段

建设管理团队与设计团队共同进行项目规划和设计,优化项目方案。进行项目的可行性研究和经济分析,确定项目的投资预算。制定项目的进度计划和质量计划。

(三)项目招标阶段

根据项目进度计划,分阶段进行施工招标。协助业主选择合适的施工承包商,签订施工合同。进行材料和设备的采购招标,确保材料和设备的质量和供应。

(四)项目施工阶段

建设管理团队对施工过程进行监督和管理,确保施工符合设计要求和相关标准规范。定期召开项目协调会议,解决施工过程中出现的问题。对项目的进度、质量、成本进行动态监控和管理,及时调整项目计划。

(五)项目竣工验收阶段

组织施工承包商进行项目竣工验收,确保项目符合验收标准。协助业主办理项目的竣工结算和交付使用手续。对项目进行总结和评价,为今后的项目管理提供经验教训。

八、辅助工具在 CM 模式中的介绍和应用

(一)辅助工具——板栗看板

板栗看板是一款协助项目管理的可视化管理工具。它通过将项目的进度、质量、成本等信息以直观的看板形式展示出来,帮助项目管理人员和相关人员及时了解项目的进展情况,发现问题并及时解决。

图片

图片

可视化展示

板栗看板可以将项目的各项信息以图表、图形、表格等形式进行可视化展示,使项目信息一目了然。项目管理人员可以通过看板快速了解项目的整体情况,包括项目进度、任务分配、资源使用情况等。

任务管理

板栗看板可以对项目任务进行详细的分解和管理。项目管理人员可以在看板上创建任务、分配任务、设置任务优先级和截止日期等。同时,看板还可以显示任务的完成情况,方便项目管理人员进行跟踪和监督。

(三)辅助工具在 CM 模式中的应用

项目进度管理

在 CM 模式中,项目进度管理是非常重要的。板栗看板可以将项目进度计划以甘特图的形式展示出来,项目管理人员可以直观地看到项目的各个阶段和任务的开始时间、结束时间和进度情况。同时,看板还可以实时更新项目进度,当出现进度偏差时,及时发出预警,提醒项目管理人员采取措施进行调整。

质量管理

质量管理是项目成功的关键之一。板栗看板可以将项目质量检查结果和质量问题以列表的形式展示出来,项目管理人员可以及时了解项目的质量状况。同时,看板还可以对质量问题的处理过程进行跟踪和管理,确保质量问题得到及时解决。

成本管理

成本管理是项目管理的重要内容。板栗看板可以将项目成本预算和实际成本支出以图表的形式展示出来,项目管理人员可以清晰地看到项目成本的变化情况。同时,看板还可以对成本超支的原因进行分析和预警,帮助项目管理人员采取措施进行成本控制。

沟通协作管理

在 CM 模式中,沟通协作非常重要。板栗看板可以为项目管理人员和相关人员提供一个便捷的沟通协作平台。项目管理人员可以在看板上发布项目通知、任务分配、问题反馈等信息,相关人员可以及时回复和处理。同时,看板还可以记录沟通协作的过程和结果,方便后续查询和追溯。

Flink 中的应用部署:当前状态与新应用模式

作为现代企业的重要工具,流处理和实时分析这类工具逐渐兴起,越来越多的企业以 Apache Flink 为核心构建平台,并将其作为服务在内部提供。在最新举办的 Flink Forward 会议中, Uber、 Netflix 和阿里巴巴等公司的许多相关主题演讲进一步说明了这一趋势。

众多平台旨在通过减轻最终用户的所有运营负担来简化内部的 Application (应用)提交。为了提交 Flink 应用程序,这些平台通常只公开一个集中式或低并行度端点(例如 Web 前端)用于应用提交,我们将调用 Deployer(部署器)。

平台开发人员和维护人员经常提到的障碍之一是,Deployer 可能是一个很难配置的大量资源消耗者。如果按照平均负载进行配置,可能会导致 Deployer 服务被部署请求淹没(在最坏的情况下,短时间内对所有生产应用程序都是如此),而按照最高负载进行规划的话,又会带来不必要的成本。根据这一观察结果,Flink 1.11 引入了 Application 模式(应用模式)作为部署选项,它允许一个轻量级、更可伸缩性的应用提交过程,从而使应用程序部署负载更均匀地分布在集群的各个节点上。

为了理解这个问题以及了解 Application 模式如何解决该问题,我们首先简要概述 Flink 中应用程序执行的当前状态,然后再阐述部署模式引入的架构变化以及如何利用它们。

Flink 中的应用程序执行

在 Flink 中执行应用程序主要涉及三个实体:Client(客户端)、JobManager(作业管理器)和 TaskManager(任务管理器)。Client 负责将应用提交给集群,JobManager 负责执行期间必要的 bookkeeping,而 TaskManager 则负责实际的计算。更多细节请参考 Flink 的架构 文档。

当前部署模式

在 1.11 版本中引入 Application 模式之前,Flink 允许用户在 Session(会话)或 Per-Job 集群上执行应用程序。两者之间的差异与集群生命周期和它们提供的资源隔离保证有关。

Session 模式

Session 模式(会话模式)假定集群已经运行,并使用该集群的资源来执行任何提交的应用程序。在同一(Session)集群中执行的应用程序使用相同的资源,并因此相互竞争。这样做的好处是,你无需为每个提交的作业分配整个集群的资源开销。但是,如果其中一个作业行为不正常或者关闭了 TaskManager,那么在该 TaskManager 上运行的所有作业都将受到故障的影响。除了对导致故障的作业产生负面影响之外,这还意味着潜在的大规模恢复过程,即所有重新启动的作业同时访问文件系统,并使其不可用于其他服务。此外,单个集群运行多个作业意味着 JobManager 的负载更大,它负责集群中所有作业的 bookkeeping。这种模式非常适合启动短作业,例如交互式查询。

Per-Job 模式

在 Per-Job 模式中,可用的集群管理器框架(如 YARN 或 Kubernetes)用于为每个提交的作业启动 Flink 集群,该集群仅对该作业可用。当作业完成后,集群将关闭,并清理所有延迟的资源(例如文件)。这种模式允许更好的资源隔离,因为行为不正常的作业不会影响任何其他作业。另外,由于每个应用程序都有自己的 JobManager,因此它将 bookkeeping 负载分散到多个实体。考虑到前面提到的 Session 模式中的资源隔离问题,对于长时间运行的作业,用户经常选择 Per-Job 模式,因为这些作业愿意接受一定程度的启动延迟的增加,以支持弹性。

总之,在 Session 模式中,集群生命周期独立于集群中运行的任何作业,并且集群中运行的所有作业共享其资源。Per-Job 模式选择为每个提交的作业分配一个集群,已提供更好的资源隔离保证,因为资源不会在作业之间共享。在这种情况下,集群的生命周期与作业的生命周期相关。

Application 提交

Flink 应用程序的执行包括两个阶段:pre-flight,即当用户的 main() 方法被调用时;runtime,即用户代码调用 execute()时立即触发。main() 方法使用 Flink 的 API(DataStream API、Table API、DataSet API)之一构造用户程序。当 main() 方法调用 env.execute() 时,用户定义的管道将被转换成一种 Flink 运行时可以理解的形式,称为 Job Graph(作业图),并将其传递给集群。

尽管它们方法有所不同,Session 模式和 Per-Job 模式都会在 Client 执行应用程序的 main() 方法,即 pre-flight 阶段。

对于已经在本地拥有作业的所有依赖项,然后通过在其机器上运行的 Client 提交其应用程序的单个用户来说,这通常不是问题。但是,对于通过远程实体(如 Deployer)提交的情况下,这个过程包括:

  • 本地下载应用程序的依赖项;
  • 执行 main() 方法提取 Job Graph;
  • 将 Job Graph 及其依赖项发送到集群以便执行;
  • 等待结果。

这使得 Client 消耗了大量的资源,因为它可能需要大量的网络带宽来下载依赖项或将二进制文件发送到集群,并且需要 CPU 周期来执行 main() 方法。随着越来越多的用户共享同一个 Client,这个问题甚至会变得更加突出。

上图展示了使用红色、蓝色和绿色表示的三个应用程序的两种部署模式。每个矩形都有三个并行项。黑色矩形表示不同的进程,分别是 TaskManager、JobManager 和 Deployer。我们假设在所有情况下只有一个 Deployer 进程。彩色三角形表示提交进程的负载,而彩色矩形表示 TaskManager 和 JobManager 进程的负载。如图所示,Per-Job 模式和 Session 模式下的 Deployer 共享相同的负载。它们的不同之处在于任务的分配和 JobManager 负载。在 Session 模式下,集群中的所有作业都有一个 JobManager,而在 Per-Job 模式下,每个作业都有一个 JobManager。此外,Session 模式下的任务会随机分配给 TaskManager,而在 Per-Job 模式下,每个 TaskManager 只能有单个作业任务。

Application 模式

Application 模式建立在上述观察结果的基础上,并尝试将 Per-Job 模式的资源隔离与轻量级且可伸缩的应用提交过程结合起来。为实现这一点,它为每个提交的应用程序创建一个集群,但是这一次,应用程序的 main() 方法在 JobManager 上执行。

为每个应用程序创建一个集群可以看作是创建一个只在特定应用程序的作业之间共享的 Session 集群,并在应用程序结束时关闭。使用这种架构,Application 模式提供与 Per-Job 模式相同的资源隔离和负载平衡保证,但在整个应用程序的粒度上。这是有道理的,因为属于同一应用程序的工作应该相互关联,并被视为一个单元。

在 JobManager 上执行 main() 方法不仅可以节省提取 Job Graph 所需的 CPU 周期,也可以节省 Client 本地下载依赖项并将 Job Graph 及其依赖项发送到集群所需的带宽。此外,由于每个应用程序只有一个 JobManager,因此,它可以更均匀地分散网络负载。上图对此进行了说明,其中我们具有与 “Session 和 Per-Job 部署模式” 部分中相同的场景,但是这一次 Client 负载已经转移到了每个应用程序的 JobManager。

注:在 Application 模式下, main() 方法是在集群上执行的,而不是像在其他模式中那样在 Client 上执行。和可能对代码产生影响,例如,使用 regsiterCachedFile() 在环境中注册的任何路径都必须由应用程序的 JobManager 进行访问。

与 Per-Job 模式相比,Application 模式允许提交由多个作业组成的应用程序。作业执行的顺序不受部署模式的影响,而是受用于启动作业的调用的影响。使用阻塞 execute() 方法建立一个顺序,并将导致下一个作业的执行被延迟到“这个”作业完成为止。相反,一旦提交了当前作业,非阻塞 executeAsync() 方法将立即继续提交“下一个”作业。

降低网络需求

如上所述,通过在 JobManager 上执行应用程序的 main() 方法,Application 模式可以节省以前在提交作业时所需的大量资源。但仍有改进的余地。

重点关注 YARN,它已经支持所有提到的 here 2,即使 Application 模式已经就绪,Client 仍然需要发送用户 Jar 到 JobManager。此外,对于每个应用程序,Client 必须将 “flink-dist” 目录发送到集群,该目录包含框架本身的二进制文件,包括 flink-dist.jar 、 lib/ 和 plugin/ 目录。这两者可能会在 Client 占用大量带宽。此外,在每次提交时发送相同的 flink-dist 二进制文件既是对带宽的浪费,也是对存储空间的浪费。只需允许应用程序共享相同的二进制文件即可减少存储空间的浪费。

在 Flink 1.11 中,我们引入了医学选项,允许用户进行如下操作:

  1. 指定一个目录的远程路径,在该目录中,YARN 可以找到 Flink 分发二进制文件,以及
  2. 指定一个远程路径,YARN 可以在其中找到用户 Jar。

对于第一步,我们利用了 YARN 的分布式缓存,并允许应用程序共享这些二进制文件。因此,如果一个应用程序碰巧在它的 TaskManager 的本地存储中找到了 Flink 的副本,由于之前的一个应用程序在同一个 TaskManager 上执行,它甚至都不需要在内部下载它。

注:这两种优化都可以用于 YARN 上的所有部署模式,而不仅仅是 Application 模式。

示例:YARN 上的 Application 模式

有关完整说明,请参阅 Flink 的官方文档,更具体地说,请参阅引用集群管理框架的页面,例如 YARN 或 Kubernetes。接下来我将给出一些关于 YARN 的例子,其中上述所有功能都是可用的。

要以 Application 模式启动用用程序,可以使用:

./bin/flink run-application -t yarn-application ./MyApplication.jar

使用这条命令,所有的配置参数,例如用于引导应用程序状态的保存点的路径,或者所需的 JobManager/TaskManager 内存大小,都可以通过它们的配置选项(以 -d 作为前缀)来指定。有关可用配置选项的目录,请参阅 Flink 的 配置页面。

例如,指定 JobManager 和 TaskManager 内存大小的命令如下所示:

./bin/flink run-application -t yarn-application \
-Djobmanager.memory.process.size=2048m \
-Dtaskmanager.memory.process.size=4096m \
./MyApplication.jar

最后,为了进一步节省提交应用程序 Jar 所需的带宽,可以预先将其上传到 HDFS,并指定指向 ./MyApplication.jar 的远程路径,如下所示:

./bin/flink run-application -t yarn-application \
-Djobmanager.memory.process.size=2048m \
-Dtaskmanager.memory.process.size=4096m \
-Dyarn.provided.lib.dirs="hdfs://myhdfs/remote-flink-dist-dir" \
hdfs://myhdfs/jars/MyApplication.jar

这将使作业提交变得更加轻量级,因为所需的 Flink jar 和应用程序 Jar 将从指定的远程位置提取,而不是由 Client 发送到集群。Client 将唯一提供给集群的是应用程序的配置,其中包括上述提到的所有路径。

总结

我们希望本文的讨论能够帮助你理解 Flink 提供的各种部署模式之间的差异,并且能够帮助你作出明智的决定,究竟哪一种模式适合你自己的设置。

作者介绍:

Kostas Kloudas,Apache Flink PMC Member、Committer,Ververica 软件工程师。

原文链接:

https://flink.apache.org/news/2020/07/14/application-mode.html

关于终端/ zsh / terminfo中的应用模式是什么?终端terminal的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于C#中的资源释放模式是什么?、ccflow 在基于最新版本的实现原理是什么?涉及的架构模式是什么?、CM模式是什么?如何应用?、Flink 中的应用部署:当前状态与新应用模式的相关知识,请在本站寻找。

本文标签: