标签:style blog http color 使用 os io 数据
我经常访问Xorg的官网,希望能找到一些对理解Linux和X Window有用的东西。结果也确实是偶有所得。比如,在Xorg的官网中就建议大家不用Xlib了,改用XCB。不可否认,Xlib确实是一个比较老的东西,老到最新的一本关于Xlib的书都已经是N多年前出版的了。有了Xorg官方的指导,我自然不用学Xlib了,直接上XCB。
经过这一段时间的学习,对XCB有了一定的了解。我的学习是根据XCB官方的教程来的,当然,如果有一点点在GUI编程领域的经验和悟性学习起来会更加事半功倍。在XCB的官方教程中,一开篇就提出XCB比Xlib先进的地方,同时给出一个示例程序证明XCB比Xlib快多少。但是,对于没有一点Xlib和XCB基础的人来说,要理解这个程序确实有点难。但是现在回过头去看这个教程的开头,一切都是那么一目了然。
XCB取代Xlib大致上有这样一些理由:
1、Xlib太重量级了,不易转型,而XCB则轻量级得多;
2、虽然说Xlib是最靠近X协议的底层开发库,但是其实它还不够底层,因为它提供了缓存机制,而XCB没有缓存,一切都是直接操作X协议,比Xlib还要底层;
3、据说Xlib对新的X扩展支持不好;
4、Xlib对多线程编程支持不好,虽然它努力过,但是基础没打好,所以怎么努力也干不好这件事,而XCB没有历史负担,适用于多线程编程;
5、Xlib和X Server的通讯时同步的,而XCB是异步的,所以XCB比Xlib要快得多。
我这里重点展示第5点。在前面一篇中我对XCB的异步机制有具体的展示。XCB的异步机制其实就是向服务器提交一个请求后,不用等待服务器的答复就可以继续提交后面的请求,因此,不会因为数据在网络上传输的时间而影响程序的效率。而Xlib向X Server提交一个请求后,必须等到服务器答复,才能提交下一个请求。
下面是一个示例程序,在这个程序中,分别以好的方式和坏的方式使用XCB和Xlib,请求服务器创建500个Atom,比较XCB和Xlib分别花的时间。很幸运,关于Atom上一篇中也提到了,所以不陌生。使用Xlib的坏的方式是一个一个地调用XInternAtom()函数,每次都要等服务器返回后才能创建下一个Atom,所以这是最慢的方式,而使用Xlib的好的方式是使用XInternAtoms()函数一次性创建500个Atom。而使用XCB的坏的方式是,每次调用xcb_intern_atom()函数后,再调用xcb_intern_atom_reply(),确认服务器答复后再创建下一个Atom,很显然这是一个较慢的方式,而且,由于和服务器的一次对话需要调用两个函数,所以使用起来比Xlib还要麻烦。而使用XCB的好的方式,当然是一股脑调用500次xcb_intern_atom()函数,这500次调用完成之后再来关注服务器的答复。示例代码如下,我基本照抄了XCB教程中的代码,只改了最后的几句printf。
1 /* It‘s a good idea to paste this and other long code examples
2 into a text editor for easier reading */
3
4 #include 5 #include 6 #include string.h>
7 #include 8 #include 9 #include 10 #define NUM_NAMES 500
11 /*
12 NOTE: For concision, we‘re going to be cheesy and use arrays where real code
13 would use points and memory allocation.s
14 */
15 #ifndef __GNUC__
16 char* strdup(const char* s) {
17 int n = strlen(s) + 1;
18
19 char *dup = malloc(n);
20
21 if(dup)
22 strcpy(dup, s);
23
24 return dup;
25 }
26 #endif
27
28 /*
29 return interval of time (uses time.h)
30 */
31 double
32 get_time (void) {
33 struct timeval timev;
34 gettimeofday(&timev, NULL);
35 return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
36 }
37
38 /*
39
40 */
41 void
42 useXlib (char **names,
43 Display *display ) {
44
45 Atom atoms[NUM_NAMES];
46 for (int i = 0; i i) {
47 atoms[i] = XInternAtom(display, names[i], 0);
48 }
49 }
50
51 /*
52 Request all atoms at once.
53 */
54 void
55 useXlibProperly (char **names,
56 Display *display ) {
57
58 Atom atoms[NUM_NAMES];
59 if(!XInternAtoms(display, names, NUM_NAMES, 0, atoms))
60 fprintf(stderr, "XInternAtoms failed\n");
61 }
62
63 /*
64
65 */
66 void
67 useXCBPoorly (char **names,
68 xcb_connection_t *connection ) {
69 xcb_atom_t atoms[NUM_NAMES];
70 // in this bad use of xcb, we use the cookie immediately after posting the request with xcb_intern_atom
71 for (int i = 0; i i) {
72 /* make request */
73 xcb_intern_atom_cookie_t cookie = xcb_intern_atom (connection,
74 0,
75 strlen(names[i]),
76 names[i] );
77 /* get response */
78 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply (connection,
79 cookie,
80 NULL ); // normally a pointer to receive error, but we‘ll
81
82 just ignore error handling
83 if (reply) {
84 atoms[i] = reply->atom;
85 free (reply);
86 }
87 }
88 // now we have our atoms (replies), but this is just a demo, so we do nothing with them
89 }
90
91 /*
92 */
93 void
94 useXCBProperly (char **names,
95 xcb_connection_t *connection ) {
96 xcb_atom_t atoms[NUM_NAMES];
97 xcb_intern_atom_cookie_t cookies[NUM_NAMES];
98 // in this good example, we make all our requests before checking for
99 // replies because it‘s best to queue requests when we have many at once
100 /* make requests */
101 for (int i = 0; i i) {
102 cookies[i] = xcb_intern_atom (connection,
103 0,
104 strlen (names[i]),
105 names[i] );
106 }
107 /* get responses */
108 for (int i = 0; i i) {
109 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply (connection,
110 cookies[i],
111 NULL ); // normally a pointer to receive errors, but we‘ll
112
113 just ignore error handling
114 if (reply) {
115 atoms[i] = reply->atom;
116 free (reply);
117 }
118 }
119 // now we have our atoms (replies), but this is just a demo, so we do nothing with them
120 }
121
122 int
123 main () {
124 /* setup names for tests */
125 char (**names) = malloc(NUM_NAMES*sizeof(*names));
126 // init names to "NAME0", "NAME1", "NAME2" ... and so on
127 for (int i = 0; i i) {
128 char buf[100];
129 sprintf (buf, "NAME%d", i);
130 names[i] = strdup (buf);
131 }
132
133 /* do tests */
134 double start, XlibTime, XlibGoodTime, XCBBadTime, XCBGoodTime;
135
136 /* test Xlib */
137 Display *display = XOpenDisplay (NULL);
138 start = get_time ();
139 useXlib (names, display);
140 XlibTime = get_time () - start;
141 start = get_time ();
142 useXlibProperly (names, display);
143 XlibGoodTime = get_time () - start;
144 XCloseDisplay (display);
145
146 /* test XCB */
147 xcb_connection_t *connection = xcb_connect (NULL, NULL);
148 start = get_time ();
149 useXCBPoorly (names, connection);
150 XCBBadTime = get_time () - start;
151 start = get_time ();
152 useXCBProperly (names, connection);
153 XCBGoodTime = get_time () - start;
154 xcb_disconnect (connection);
155
156 /* report times */
157 printf ("Bad Xlib time : %f\n", XlibTime);
158 printf ("Good Xlib time : %f\n", XlibGoodTime);
159 printf ("Bad xcb time : %f\n", XCBBadTime);
160 printf ("Good xcb time : %f\n", XCBGoodTime);
161 printf ("ratio of bad xcb time to good xcb time: %f\n", XCBBadTime / XCBGoodTime);
162 printf ("ratio of bad Xlib time to good Xlib time: %f\n", XlibGoodTime / XlibTime);
163 printf ("ratio of bad Xlib time to good XCB time: %f\n", XlibTime / XCBGoodTime);
164 printf ("ratio of good Xlib time to good xcb time: %f\n", XlibGoodTime / XCBGoodTime);
165 return 0;
166 }
运行效果如下图:
从图中可以看出,XCB的异步方式比同步的方式要快几十倍,Xlib好的方式比坏的方式要快100多倍。由于XCB默认就是异步的,而Xlib天生是同步的,所以最好的和最坏的比较,效率相差300多倍。这就是XCB取代Xlib的理由。
(京山游侠于2014-08-01发布于博客园,转载请注明出处。)
使用XCB编写X Window程序(06):XCB取代Xlib的理由,搜素材,soscw.com
使用XCB编写X Window程序(06):XCB取代Xlib的理由
标签:style blog http color 使用 os io 数据
原文地址:http://www.cnblogs.com/youxia/p/gui006.html