流水线电子看板的设计与实现

项目背景

我集团公司流水线上的生产,每一个部件、产品完工后,都会贴上预先打印好的条形码,并且通过扫描枪扫描入系统。公司已有一套外购系统完成对流水线数据的采集。高层从"智能制造"理念出发,需要推广电子看板来监督流水线的作业效率。主要有三点功能要求:

1. 采集扫描枪的数据,绘制实时动态曲线图;

2. 当作业节拍(曲线图纵坐标)超过SAP系统中的规定值,停线报警;

3. 作业单完工后,数据自动保存,网络不佳时保存在本地,不影响流水线作业。

总体设计

由于产线已配置电脑和系统对扫描数据做采集,从节约成本的方向考虑,本系统继续安装在产线电脑上。显示方式上,将采用分屏显示的效果实现(一台电脑接两个显示器显示不同内容,后期其中一台显示器转为接高清电视机显示本系统)。另外产线的xp系统需升级为win7系统。在离线数据存储上,采用MSMQ实现临时数据存储(同时也能极大的减轻数据库压力)。未来的方向是统一将各客户端的临时数据集中发送到一台中转站机器的MSMQ中,再在空闲时段将数据发送至数据库服务器。前期,MSMQ将存储在本地,并在本系统单独开一进程隔一段时间向数据库推送完工作业单的数据。同时,由于鼠标焦点不在本系统上,为方便使用全局钩子获取扫描枪信息,本系统采用Winform技术实现。

原型图&框架

原型图说明:实际操作中,产线用户始终在操作和聚焦右边的主显示器窗口;左边的扩展显示器显示本系统(电子看板)【两台显示器虽共用一个主机,但显示了不同内容】。电子看板将实时绘制曲线图显示作业效率,如果作业效率低于SAP规定的值,则停线报警。(直观理解是两次扫描的时间过长则会想起警报...)

本系统主要的功能点集中在实时动态图表所在的窗口上。即便如此,从后期扩展的方向考虑,我还是搭建了一个系统框架。

使用LinqToSQL做为ORM的简单三层,由于时间紧迫,暂时缺少权限和日志系统,这是现存的不足。

技术难点&核心代码

一. 实时动态图表

本系统最大的难点,包括:a)使用全局钩子收集扫描枪数据; b)是实时动态图表的实现。

a). 全局钩子收集扫描枪数据

修改了下网上流行的"条形码钩子"类,网上流行的版本,当条形码第一个字符是字母的时候,有一些问题。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Runtime.InteropServices;
  6 using System.Reflection;
  7 using System.Diagnostics;
  8
  9 namespace Barcode
 10 {
 11     /// <summary>
 12     /// 条形码钩子
 13     /// </summary>
 14     public class BarCodeHook
 15     {
 16         public delegate void BarCodeDelegate(BarCodes barCode);
 17         public event BarCodeDelegate BarCodeEvent;
 18
 19         public struct BarCodes
 20         {
 21             public int VirtKey;      //虚拟码
 22             public int ScanCode;     //扫描码
 23             public string KeyName;   //键名
 24             public uint AscII;       //AscII
 25             public char Chr;         //字符
 26
 27             public string BarCode;   //条码信息
 28             public bool IsValid;     //条码是否有效
 29             public DateTime Time;    //扫描时间
 30         }
 31
 32         private struct EventMsg
 33         {
 34             public int message;
 35             public int paramL;
 36             public int paramH;
 37             public int Time;
 38             public int hwnd;
 39         }
 40
 41         //键盘Hook结构函数
 42         [StructLayout(LayoutKind.Sequential)]
 43         public class KeyBoardHookStruct
 44         {
 45             public int vkCode;
 46             public int scanCode;
 47             public int flags;
 48             public int time;
 49             public int dwExtraInfo;
 50         }
 51
 52         /// <summary>
 53         /// 监控消息窗口的钩子
 54         /// </summary>
 55         /// <param name="idHook"></param>
 56         /// <param name="lpfn"></param>
 57         /// <param name="hInstance"></param>
 58         /// <param name="threadId"></param>
 59         /// <returns></returns>
 60         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
 61         private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
 62
 63         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
 64         private static extern bool UnhookWindowsHookEx(int idHook);
 65
 66         [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
 67         private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
 68
 69         [DllImport("user32", EntryPoint = "GetKeyNameText")]
 70         private static extern int GetKeyNameText(int lParam, StringBuilder lpBuffer, int nSize);
 71
 72         [DllImport("user32", EntryPoint = "GetKeyboardState")]
 73         private static extern int GetKeyboardState(byte[] pbKeyState);
 74
 75         [DllImport("user32", EntryPoint = "ToAscii")]
 76         private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeyState, ref uint lpChar, int uFlags);
 77
 78         [DllImport("kernel32.dll")]
 79         public static extern IntPtr GetModuleHandle(string name);
 80
 81         [DllImport("user32.dll")]
 82         public static extern void SetCursorPos(int x, int y);
 83
 84         delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
 85
 86         BarCodes barCode = new BarCodes();
 87         int hKeyboardHook = 0;
 88         //此处使用char List 避免了原有代码中扫描出的结果是乱码的情况
 89         List<char> _barcode = new List<char>(100);
 90         private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
 91         {
 92             if (nCode == 0)
 93             {
 94                 EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
 95                 if (msg.message == (int)System.Windows.Forms.Keys.H && (int)System.Windows.Forms.Control.ModifierKeys == (int)System.Windows.Forms.Keys.Control + (int)System.Windows.Forms.Keys.Alt)  //截获Ctrl+Alt+H
 96                 {
 97                     SetCursorPos(200, 200);//组合键使鼠标回到主屏幕
 98                 }
 99                 if (wParam == 0x100)   //WM_KEYDOWN = 0x100
100                 {
101                     barCode.VirtKey = msg.message & 0xff;  //虚拟码
102                     barCode.ScanCode = msg.paramL & 0xff;  //扫描码
103
104                     StringBuilder strKeyName = new StringBuilder(255);
105                     if (GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0)
106                     {
107                         barCode.KeyName = strKeyName.ToString().Trim(new char[] { ‘ ‘, ‘\0‘ });
108                     }
109                     else
110                     {
111                         barCode.KeyName = "";
112                     }
113
114                     byte[] kbArray = new byte[256];
115                     uint uKey = 0;
116                     GetKeyboardState(kbArray);
117                     if (ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0))
118                     {
119                         barCode.AscII = uKey;
120                         barCode.Chr = Convert.ToChar(uKey);
121                     }
122
123                     if (DateTime.Now.Subtract(barCode.Time).TotalMilliseconds > 50)
124                     {
125                         _barcode.Clear();
126                     }
127                     else
128                     {
129                         if ((msg.message & 0xff) == 13 && _barcode.Count > 0)   //回车
130                         {
131                             barCode.BarCode = new String(_barcode.ToArray());
132                             barCode.IsValid = true;
133                         }
134                         if (msg.message != 160)//加对空格的排除处理
135                             _barcode.Add(Convert.ToChar(msg.message & 0xff));
136                     }
137
138                     barCode.Time = DateTime.Now;
139                     if (BarCodeEvent != null) BarCodeEvent(barCode);    //触发事件
140                     barCode.IsValid = false;
141                 }
142             }
143             return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
144         }
145
146         //增加了一个静态变量,放置GC将钩子回收掉
147         private static HookProc hookproc;
148         // 安装钩子
149         public bool Start()
150         {
151             if (hKeyboardHook == 0)
152             {
153                 hookproc = new HookProc(KeyboardHookProc);
154                 //WH_KEYBOARD_LL = 13
155                 //hKeyboardHook = SetWindowsHookEx(13, hookproc, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
156
157                 //使用全局钩子
158                 IntPtr modulePtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
159                 hKeyboardHook = SetWindowsHookEx(13, hookproc, modulePtr, 0);
160             }
161             return (hKeyboardHook != 0);
162         }
163
164         // 卸载钩子
165         public bool Stop()
166         {
167             if (hKeyboardHook != 0)
168             {
169                 return UnhookWindowsHookEx(hKeyboardHook);
170             }
171             return true;
172         }
173
174     }
175 }

b). 动态实时图表

根据扫描枪的扫描信号,实时绘制曲线图,并且当数据超出x轴量程时绘图自动向左滚动。这里采用微软MSChart图表实现。

图表初始化

 1         private void InitChart()
 2         {
 3             #region 初始化时,设置 X 轴的刻度初始值
 4             //设置X轴量程
 5             chart1.ChartAreas[0].AxisX.Minimum = DateTime.Now.ToOADate();
 6             chart1.ChartAreas[0].AxisX.Maximum = DateTime.Now.AddHours(4).ToOADate();
 7             //设置X轴间隔类型
 8             chart1.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Hours;
 9             chart1.ChartAreas[0].AxisX.Interval = 0.5;
10             //设置X轴网格间距类型
11             chart1.ChartAreas[0].AxisX.MajorGrid.IntervalType = DateTimeIntervalType.Hours;
12             chart1.ChartAreas[0].AxisX.MajorGrid.Enabled = true;
13             //设置时间格式
14             chart1.ChartAreas[0].AxisX.LabelStyle.Format = "HH:mm:ss";
15             chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 0.5;
16             #endregion
17
18             #region 画板样式
19             chart1.ChartAreas[0].BackColor = Color.Black;
20             #endregion
21
22             #region 曲线图初始值设置
23             chart1.Series[0].LegendText = "节拍";
24             chart1.Series[0].ChartType = SeriesChartType.Spline;
25             //chart1.Series[0].BorderWidth = 1;
26             chart1.Series[0].Color = Color.Green;
27             chart1.Series[0].ShadowOffset = 1;
28             chart1.Series[0].XValueType = ChartValueType.DateTime;
29             chart1.Series[0].Points.AddXY(chart1.ChartAreas[0].AxisX.Minimum, 8);
30             //chart1.Series[0].IsValueShownAsLabel = true;//显示曲线上点的数值
31             #endregion
32         }

绘图

 1 /// <summary>
 2         /// 绘图
 3         /// </summary>
 4         /// <param name="currentTime"></param>
 5         /// <param name="Beats"></param>
 6         private void AddData(DateTime currentTime,double Beats)
 7         {
 8             foreach (Series ptSeries in chart1.Series)
 9             {
10                 // Add new data point to its series.
11                 ptSeries.Points.AddXY(currentTime.ToOADate(), Beats);
12                 //到3/4刻度,向左滚动
13                 double removeBefore = currentTime.AddHours((double)(3) * (-1)).ToOADate();
14                 //remove oldest values to maintain a constant number of data points
15                 while (ptSeries.Points[0].XValue < removeBefore)
16                 {
17                     ptSeries.Points.RemoveAt(0);
18                 }
19                 //设置X轴量程,如果不设置间隔,间隔会自动进行计算(这里是每次重绘图案,都重新设置间隔)
20                 chart1.ChartAreas[0].AxisX.Minimum = ptSeries.Points[0].XValue;
21                 chart1.ChartAreas[0].AxisX.Maximum = DateTime.FromOADate(ptSeries.Points[0].XValue).AddHours(4).ToOADate();
22                 //重绘图案
23                 chart1.Invalidate();
24             }
25         }

二. MSMQ的使用

当然使用前需安装MSMQ(控制面板->程序和功能->打开或关闭Windows功能),关于MSMQ这里暂不做过多介绍。本系统使用MSMQ用于缓解数据库压力和数据离线存储。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Messaging;
 6 using ALIBoardModel.Model;
 7 using ALIBoardBLL;
 8 using ALIBoardModel.Config;
 9 using DataAccess.Result;
10
11 namespace ALIBoardCore
12 {
13     /// <summary>
14     /// MSMQ消息队列(使用单例模式确保私有队列的唯一性)
15     /// </summary>
16     public class ALIMSMQ
17     {
18         private MessageQueue mq = null;
19
20         private static ALIMSMQ _instance = null;
21
22         private WorkInfoBLL bll = new WorkInfoBLL(Connect.ALIConnStr);
23
24         private ALIMSMQ()
25         {
26             if (!MessageQueue.Exists(@".\private$\ALIQueue"))
27                 mq = MessageQueue.Create(@".\private$\ALIQueue");
28             mq = new MessageQueue(@".\private$\ALIQueue");
29         }
30
31         public static ALIMSMQ GetInstance()
32         {
33             if (_instance == null)
34                 _instance = new ALIMSMQ();
35             return _instance;
36         }
37
38         public void SendMQ(object obj)
39         {
40             mq.Send(obj);
41         }
42
43         public Message ReceiveAndDelete()
44         {
45             return mq.Receive();//取出第一条消息并删除其在队列中的位置
46         }
47
48         public void SendDataToDatabase()
49         {
50             //指定读取消息的格式化程序
51             mq.Formatter = new XmlMessageFormatter(new Type[] { typeof(WorkInfo) });
52             foreach (Message m in mq.GetAllMessages())
53             {
54                 try
55                 {
56                     WorkInfo info = m.Body as WorkInfo;
57                     if(info != null)
58                         info.SyncDate = DateTime.Now;
59                     CommandResult result = bll.Insert(info);
60                     if(result.Result == ResultCode.Successful)
61                         mq.ReceiveById(m.Id);
62                 }
63                 catch (Exception e)
64                 {
65                 }
66             }
67         }
68     }
69 }

三. C#连接SAP,调用SAP RFC接口

a). 主要实现代码(使用SAP NCO3.0)

SAPConfig类

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using SAP.Middleware.Connector;
 6
 7 namespace SAP
 8 {
 9     /// <summary>
10     /// 实现IDestinationConfiguration接口成员
11     /// </summary>
12     public class SAPConfig : IDestinationConfiguration
13     {
14         public RfcConfigParameters GetParameters(String destinationName)
15         {
16             if ("MES_ATIBoard_SAP001".Equals(destinationName))
17             {
18                 RfcConfigParameters parms = new RfcConfigParameters();
19                 parms.Add(RfcConfigParameters.AppServerHost, Connect.SAPServer);//SAP服务器
20                 parms.Add(RfcConfigParameters.SystemNumber, Connect.SAPSystemNumber);  //SAP系统编号
21                 parms.Add(RfcConfigParameters.User, Connect.SAPUser);  //用户名
22                 parms.Add(RfcConfigParameters.Password, Connect.SAPPassword);  //密码
23                 parms.Add(RfcConfigParameters.Client, Connect.SAPClient);  // Client(集团)
24                 parms.Add(RfcConfigParameters.Language, Connect.SAPLanguage);  //登陆语言
25                 parms.Add(RfcConfigParameters.PoolSize, "5");
26                 parms.Add(RfcConfigParameters.MaxPoolSize, "20");
27                 parms.Add(RfcConfigParameters.IdleTimeout, "60");
28                 return parms;
29             }
30             return null;
31         }
32
33         public bool ChangeEventsSupported()
34         {
35             return false;
36         }
37
38         public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;
39     }
40 }

RFC类

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5
  6 using SAP.Middleware.Connector;
  7 using System.Data;
  8
  9 namespace SAP
 10 {
 11     public class RFC : IDisposable
 12     {
 13         IDestinationConfiguration ID = new SAPConfig();
 14         public void Dispose()
 15         {
 16             RfcDestinationManager.UnregisterDestinationConfiguration(ID);
 17         }
 18
 19         /// <summary>
 20         /// 获取装配工艺的sap信息
 21         /// </summary>
 22         /// <param name="_MATNR">输入参数(工单号,如:200026179)</param>
 23         /// <returns></returns>
 24         public SAPInfo GetSAPInfo(string _MATNR)
 25         {
 26             RfcDestinationManager.RegisterDestinationConfiguration(ID);
 27             RfcDestination prd = RfcDestinationManager.GetDestination("MES_ATIBoard_SAP001");
 28
 29             RfcRepository repo = prd.Repository;
 30             IRfcFunction companyBapi = repo.CreateFunction("ZMES_PRODUCEORDER_WORKTIME"); //调用函数名
 31             companyBapi.SetValue("IM_AUFNR", _MATNR); //设置Import的参数
 32             companyBapi.Invoke(prd);   //执行函数
 33
 34             IRfcTable table = companyBapi.GetTable("WT_ITEM");  //获取相应的品号内表
 35
 36             if (table.RowCount > 0)
 37             {
 38                 DataTable dt = GetDataTableFromRFCTable(table);
 39                 for (int i = 0; i < dt.Rows.Count; i++)
 40                 {
 41                     object keyColumnName = dt.Rows[i]["LTXA1"];
 42                     if (keyColumnName != null && keyColumnName.ToString().Trim() == "装配")
 43                     {
 44                         SAPInfo sap = new SAPInfo();
 45                         sap.SAPOrderID = dt.Rows[i]["AUFNR"].ToString();
 46                         sap.ProductCode = dt.Rows[i]["PLNBEZ"].ToString();
 47                         sap.WorkCount = Convert.ToDouble(dt.Rows[i]["GAMNG"]);
 48                         sap.WTIME = Convert.ToDouble(dt.Rows[i]["WTIME"]);
 49                         return sap;
 50                     }
 51                 }
 52             }
 53             return null;
 54         }
 55
 56         #region 私有方法
 57         private DataTable GetDataTableFromRFCTable(IRfcTable myrfcTable)
 58         {
 59             DataTable loTable = new DataTable();
 60             int liElement = 0;
 61             for (liElement = 0; liElement <= myrfcTable.ElementCount - 1; liElement++)
 62             {
 63                 RfcElementMetadata metadata = myrfcTable.GetElementMetadata(liElement);
 64                 loTable.Columns.Add(metadata.Name);
 65             }
 66             foreach (IRfcStructure Row in myrfcTable)
 67             {
 68                 DataRow ldr = loTable.NewRow();
 69                 for (liElement = 0; liElement <= myrfcTable.ElementCount - 1; liElement++)
 70                 {
 71                     RfcElementMetadata metadata = myrfcTable.GetElementMetadata(liElement);
 72                     ldr[metadata.Name] = Row.GetString(metadata.Name);
 73                 }
 74                 loTable.Rows.Add(ldr);
 75             }
 76             return loTable;
 77         }
 78         #endregion
 79     }
 80
 81     public class SAPInfo
 82     {
 83         /// <summary>
 84         /// SAP订单号
 85         /// </summary>
 86         public string SAPOrderID { get; set; }
 87         /// <summary>
 88         /// SAP产品编码(物料编码)
 89         /// </summary>
 90         public string ProductCode { get; set; }
 91         /// <summary>
 92         /// SAP作业单数量
 93         /// </summary>
 94         public double WorkCount { get; set; }
 95         /// <summary>
 96         /// SAP标准工时
 97         /// </summary>
 98         public double WTIME { get; set; }
 99     }
100
101 }

调用

                SAP.SAPInfo sap = null;
                using(SAP.RFC rfc = new SAP.RFC())
                {
                    sap = rfc.GetSAPInfo(mesOrderID);
                }

b). 问题

初次调用SAP接口,调试时多多少少会有一些问题(没问题的跳过)。请下载以下文件尝试安装解决:

SAP NCO 3.0 32位系统安装文件  sapnco30dotnet40P_8-20007347(32).zip

SAP NCO 3.0 64位系统安装文件  sapnco30dotnet40P_12-20007348(64).zip

Microsoft Visual C++ 2005       vcredist2005sp1_x86_XiaZaiBa.zip

注意:本系统使用VS2013开发,基于.NET Framework4.0。安装完SAP NCO 3.0后,在项目中引用sapnco.dll和sapnco_utils.dll即可。

系统效果图

总结

做为一个程序员,最近发现自己有一个不好的表现:当别人问我项目中有什么技术难点时,我竟只寥寥说了几个字... 对以前的一个大项目也是如此回答。我不禁反问自己:项目中真的没有难点吗?没有技术难点,那工作量是怎么出来的?时间都去哪儿了?

任何花时间做的项目,coding过程中需要查资料需要长时间思考的,自己不熟悉的,应该都归属于当前的"难点"。

虽然本系统很顺利的被我一个人断断续续的开发完成,但有一些技术自己不熟练的,还是应该重视并且记录。本系统属于一个小型项目,主要是实时动态绘图,后期很可能有一些扩展功能(报表、权限什么的...)。由于本人水平有限,在设计上如果有缺陷,还请朋友们指出。

另:出于保密因素,本系统暂时无法提供源代码下载。即使这样,核心代码都已给出。希望不会影响你的学习和参考。

希望本文对你有帮助。

时间: 2024-10-06 23:25:19

流水线电子看板的设计与实现的相关文章

流水线设计

20世纪80年代,流水线技术成为RISC处理器设计方法中最基本的技术之一,RISC的设计多以高流水为目标设计. 而后流水线技术也被应用到CISC处理器 在流水线的发展史上主要有两种流水线,算术流水线和指令流水线. 首先通过算术流水线的例子,介绍流水线理想假设. 流水线意味着将系统分割为许多段,段与段之间增加合适的缓冲,这样每隔D/K个时间单位就可以启动新的任务,而不是每隔D个时间单位. 流水线并不能被无限制的增加下去,因为时钟的限制(setup time/clock uncertainty),流

自己动手写CPU之第七阶段(5)——流水线暂停机制的设计与实现

将陆续上传本人写的新书<自己动手写CPU>,今天是第28篇,我尽量每周四篇 China-pub的预售地址如下(有目录.内容简介.前言): http://product.china-pub.com/3804025 亚马逊的预售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 7.5 流水线暂停机制的设计与实现 7.5.1 流水线暂停机制设计 因为OpenMIPS设计乘累加.乘累减.除法

流水线,耶!

??? ?最近,应航天系统登月部门的测试需求,成功模仿CPU的流水线原理做出设计,满足了对方的需求,感觉真的很爽,终于再次验证了,知识都是相通的,立竿见影的绚丽技巧性的知识都很肤浅,潜移默化的平淡基础性的知识都很王道,看来以后我得加强数学方面的学习了,目前这是一个短板,不知道大学时为什么突然不想学数学了,真的很遗憾!??? 流水线设计,总线设计,真的很酷,虽然看不到,但是却是很酷!

CPU流水线探秘之旅

作为程序员,CPU在我们的工作中扮演了核心角色,因此了解处理器内部的工作方式对程序员来说不无裨益. CPU是如何工作的呢?一条指令执行需要多长时间?当我们讨论某个新款处理器拥有12级流水线还是18级流水线,甚至是更深的31级流水线时,这到些都意味着什么呢? 应用程序通常会将CPU看作是黑盒子.程序中的指令按照顺序依次进入CPU,执行完之后再按顺序依次从CPU中出来,而内部到底发生了什么,我们通常并不了解. 对我们程序员来说,尤其是对做程序性能调优工作的程序员来说,学习CPU内部的细节非常必要.否

CPU流水线的探秘之旅

作为程序员,CPU在我们的工作中扮演了核心角色,因此了解处理器内部的工作方式对程序员来说不无裨益. CPU是如何工作的呢?一条指令执行需要多长时间?当我们讨论某个新款处理器拥有12级流水线还是18级流水线,甚至是更深的31级流水线时,这到些都意味着什么呢? 应用程序通常会将CPU看作是黑盒子.程序中的指令按照顺序依次进入CPU,执行完之后再按顺序依次从CPU中出来,而内部到底发生了什么,我们通常并不了解. 对我们程序员来说,尤其是对做程序性能调优工作的程序员来说,学习CPU内部的细节非常必要.否

Hadoop架构: 流水线(PipeLine)

该系列总览: Hadoop3.1.1架构体系——设计原理阐述与Client源码图文详解 : 总览 流水线(PipeLine),简单地理解就是客户端向DataNode传输数据(Packet)和接收DataNode回复(ACK)[Acknowledge]的数据通路. 整条流水线由若干个DataNode串联而成,数据由客户端流向PipeLine,在流水线上,假如DataNode A 比 DataNode B 更接近流水线 那么称A在B的上游(Upstream),称B在A的下游(Downstream).

数字集成电路设计-20-multi-cycle

引言 前面我们介绍了流水线的写法(http://blog.csdn.net/rill_zhen/article/details/45980039),流水线是数字设计中很常用的一种设计方法,可以提高运行频率,提高吞吐量. 如果组合逻辑延迟较大,一个时钟周期完成不了时,除了插入寄存器将组合逻辑拆分成流水线外,还可以采用multi-cycle的方式. multi-cycle的工作机制很简单,从给定输入之后,等待多个周期之后,再去采样输出结果. 本小节我们将通过一个小实验来说明multi-cycle的具

计算机硬件

阅读目录 一 为何要学习计算机基础 二 本节目标 三  计算机硬件发展史 四:计算机硬件介绍 4.1 处理器 4.2 存储器 4.3 磁盘 4.4 磁带 4.5 总线 4.6 启动计算机 回到顶部 一 为何要学习计算机基础 python是编程语言,即python是语言 语言有英语.法语.葡萄牙语等,但凡是语言,都是用来沟通的介质. 程序员编程的本质就是让计算机去工作,而编程语言就是程序员与计算机沟通的介质 程序员要想让计算机工作,必须知道计算机能干什么,怎么干的,这也就是我们必须学习计算机基础的

NVMe - NB的特性

翻译一下,纯粹是为了记住这些特性: NVMe provides the following benefits: ● Ultra-low latency 非常低的延迟 ● Very high throughput 非常高的吞吐量 ● Low power architecture, delivering lower power consumption and resulting in a lower Total Cost of Ownership and reduced carbon footpri