{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "활동 8a\n", "------------\n", "\n", "이 활동에서는 TXN Viewer 를 사용하여 TXN를 시각화해보자.\n", "\n", "시각화 툴이 정상적으로 동작하기 위해서는 아래의 파일들이 현재 노트북과 같은 디렉토리에 있어야 한다:\n", "* `txn_viewer_v2.py` (python2 인 경우)\n", "* `txn_viewer_v3.py` (python3 인 경우)\n", "* `txnViewer.js`\n", "\n", "자바스크립트 애니메이션 라이브러리를 쓸 수 있기 위해선 인터넷과 연결되어 있어야 한다.\n", "\n", "\n", "### 활동:\n", "\n", "강의에서 사용한 예제로 시작해보자. TXN Viewer에서는 직렬화로 구현되어 있다:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", "

TXN VIEWER

\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "

The Log

\n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "$.getScript(\"//d3js.org/d3.v3.min.js\", function () {\n", "$.getScript(\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\", function () {\n", "$.getScript(\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js\", function () {\n", "var chartNum = 0\n", "var numThreads = 2\n", "// State of the vars / system\n", "var state;\n", "\n", "// The TXNs log\n", "var txnLog;\n", "\n", "// Load data from json files\n", "var getTxns = function() {\n", " d3.json(\"txnLog.json\", function(error, json) {\n", " if (error) return console.warn(error);\n", " txnLog = json;\n", "\n", " // Make the viewer once txns data is loaded\n", " makeViewer();\n", "\n", " // Bind to window resize event as well\n", " $(window).resize(function() { \n", " makeViewer(); \n", " });\n", " });\n", "}\n", "getTxns();\n", "\n", "// Fixed parameters\n", "// We fix the width of the transaction boxes\n", "var txnWidth = 175;\n", "var txnHeight = 65;\n", "var txnPadding = 15;\n", "var colors = ['#0099CC', '#FF6666'];\n", "var tableHeaderHeight = 20;\n", "\n", "\n", "// Render the svg canvas\n", "var makeViewer = function() {\n", " $(\"#chart-\"+chartNum).html('');\n", "\n", " // Have width be relative to the width of the IPython output subarea width\n", " var W = $('.output_subarea').width() - 20;\n", " var canvasProportion = 0.7;\n", " var canvasWidth = canvasProportion * W;\n", " var canvasHeight = txnPadding + numThreads * (txnHeight + txnPadding);\n", "\n", " // Set the var table width appropriately\n", " $('#vals-'+chartNum).width((1 - canvasProportion)*W + 'px');\n", "\n", " // Top spacing (hackey)\n", " var topMargin = tableHeaderHeight + txnHeight;\n", " $(\"#top-spacer-\"+chartNum).height(topMargin);\n", " $(\"#chart-\"+chartNum).css(\"margin-top\", 0);\n", "\n", " // Make the svg canvas\n", " var svg = d3.select(\"#chart-\"+chartNum)\n", " .append('svg')\n", " .attr({\n", " 'width': canvasWidth,\n", " 'height': canvasHeight,\n", " 'x': topMargin\n", " })\n", " .style('border', '1px solid black');\n", "\n", " // Populate the timeline with transaction boxes\n", " makeTxns(svg, canvasWidth, canvasHeight);\n", "}\n", "\n", "// Lay out the transition boxes- g with rect + text\n", "// NOTE that the first txn in txnLog is a placeholder (for initial vals)!\n", "var makeTxns = function(svg, canvasWidth, canvasHeight) {\n", " \n", " // Make a group for the whole timeline for sliding animation\n", " var timelineWidth = txnPadding + (txnLog.length - 1) * (txnWidth + txnPadding);\n", " var dT = -Math.max(timelineWidth - canvasWidth);\n", " var timeline = svg.append('g')\n", " .attr({\n", " 'id': 'timeline-g-' + chartNum,\n", " 'transform': 'translate(' + dT + ',0)',\n", " 'class': 'timeline'});\n", " \n", " // Make the timeline i.e. the TXN boxes\n", " var txns = timeline.selectAll('g.txn')\n", " .data(txnLog)\n", " .enter()\n", " .append('g')\n", " .attr({\n", " 'id': function(d,i) { return 'txn-' + chartNum + '-' + (i-1); },\n", " 'transform': function(d,i) {\n", " var x = txnPadding + (i-1) * (txnWidth + txnPadding);\n", " var y = txnPadding + d.thread * (txnHeight + txnPadding);\n", " return 'translate(' + x + ',' + y + ')'; },\n", " 'class': 'txn'})\n", " txns.append('rect')\n", " .attr({\n", " 'width': txnWidth,\n", " 'height': txnHeight,\n", " 'fill': function(d) { return colors[d.thread % colors.length]; },\n", " 'stroke': 'none'});\n", " txns.append('text')\n", " .attr({\n", " 'text-anchor': 'middle',\n", " 'dominant-baseline': 'middle', // NOTE: doesn't work in IE?\n", " 'dx': 0.5*txnWidth,\n", " 'dy': 0.5*txnHeight,\n", " 'font-size': \"14\",\n", " 'fill': 'white'})\n", " .text(function(d) { return d.operation; });\n", " \n", " // Initialize the state to that of the last txn\n", " var t = txnLog.length - 1;\n", " state = txnLog[t].state;\n", "\n", " // Make the slider and state table\n", " makeTable();\n", " makeLog(t);\n", " makeSlider(svg, timeline, timelineWidth, canvasWidth, canvasHeight);\n", "}\n", "\n", "var makeSlider = function(svg, timeline, timelineWidth, canvasWidth, canvasHeight) {\n", " var slider = $(\"#slider-\"+chartNum);\n", " var line = svg.append('line')\n", " .attr({\n", " 'class': 'slider-bar',\n", " 'x1': 0,\n", " 'x2': 0,\n", " 'y1': 0,\n", " 'y2': canvasHeight,\n", " 'stroke': '#393D3D',\n", " 'stroke-dasharray': '2,2',\n", " 'opacity': 0.5});\n", " slider.width(canvasWidth);\n", " slider.slider();\n", " slider.slider('option', 'value', slider.slider('option', 'max'));\n", " slider.off(\"slide\");\n", " slider.on(\"slide\", function(e,ui) {\n", " var p = ui.value / 100.0;\n", " var w = p * canvasWidth;\n", "\n", " // move the slider bar\n", " line.attr('transform', 'translate(' + w + ',0)');\n", "\n", " // move the timeline\n", " var dT = -p * Math.max(0, timelineWidth - canvasWidth);\n", " timeline.attr('transform', 'translate(' + dT + ',0)');\n", "\n", " // Find the index of the last txn that should be active\n", " var t = 0;\n", " while (w > t*(txnPadding+txnWidth) + txnPadding + 0.5*txnWidth + dT) {\n", " t += 1;\n", " }\n", " t -= 1;\n", "\n", " // show / hide the txns\n", " for (var tt=0; tt < txnLog.length; tt++) {\n", " if (tt <= t) {\n", " $(\"#txn-\" + chartNum + '-' + tt).css('opacity', 1.0);\n", " } else {\n", " $(\"#txn-\" + chartNum + '-' + tt).css('opacity', 0.3);\n", " }\n", " }\n", "\n", " // Set the state & re-render the values table appropriately\n", " if (t >= -1) {\n", " state = txnLog[t+1].state;\n", " }\n", " makeTable();\n", " makeLog(t+1);\n", " });\n", "}\n", "\n", "var makeTable = function() {\n", " \n", " // Make the header row- var names\n", " var html = '';\n", " for (var v in state) {\n", " if (state.hasOwnProperty(v)) {\n", " html += '' + v + '';\n", " }\n", " }\n", " html += '';\n", "\n", " // Make the local / thread rows\n", " for (var r=0; r < numThreads + 1; r++) {\n", " html += '';\n", " if (r > 0) {\n", " html += 'Thread ' + r + '';\n", " } else {\n", " html += 'Main';\n", " }\n", " for (var v in state) {\n", " if (state.hasOwnProperty(v)) {\n", " html += '' + state[v][r] + '';\n", " }\n", " }\n", " html += '';\n", " }\n", " $(\"#vals-\"+chartNum).html(html);\n", "}\n", "\n", "var makeLog = function(t) {\n", " html = \"\");\n", "}\n", "});\n", "});\n", "});\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#from txn_viewer_v2 import TransactionManager # python2인 경우\n", "from txn_viewer_v3 import TransactionManager # python3인 경우\n", "\n", "# 초기값과 함게 몇 개의 스레드로 TransactionManager 객체를 생성하였다.\n", "tm = TransactionManager(n_threads=2, initial_main_vals={'A':50, 'B':200})\n", "\n", "# Step 1: 이율\n", "INTEREST_RATE = 1.06\n", "\n", "a0 = tm.read(0, 'A')\n", "tm.write(0, 'A', a0*INTEREST_RATE)\n", "\n", "b0 = tm.read(0, 'B')\n", "tm.write(0, 'B', b0*INTEREST_RATE)\n", "\n", "\n", "# Step 2: 자금 이체\n", "\n", "a1 = tm.read(1, 'A')\n", "tm.write(1, 'A', a1 + 100)\n", "\n", "b1 = tm.read(1, 'B')\n", "tm.write(1, 'B', b1 - 100)\n", "\n", "tm.display(chart_num=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 문제 1: 위의 결과의 _serializable_ 스케줄의 예를 만들어 보자\n", "\n", "총 몇 개나 만들 수 있을까? unserializable 한 경우는 몇 개나 만들 수 있나? 위의 도구를 사용하여 찾아보자. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 문제 2: 다음 문제에서는 어떤 종류의 이상현상이 생기나?" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", "

TXN VIEWER

\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "
\n", "
\n", "
\n", "

The Log

\n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "$.getScript(\"//d3js.org/d3.v3.min.js\", function () {\n", "$.getScript(\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\", function () {\n", "$.getScript(\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js\", function () {\n", "var chartNum = 1\n", "var numThreads = 3\n", "// State of the vars / system\n", "var state;\n", "\n", "// The TXNs log\n", "var txnLog;\n", "\n", "// Load data from json files\n", "var getTxns = function() {\n", " d3.json(\"txnLog.json\", function(error, json) {\n", " if (error) return console.warn(error);\n", " txnLog = json;\n", "\n", " // Make the viewer once txns data is loaded\n", " makeViewer();\n", "\n", " // Bind to window resize event as well\n", " $(window).resize(function() { \n", " makeViewer(); \n", " });\n", " });\n", "}\n", "getTxns();\n", "\n", "// Fixed parameters\n", "// We fix the width of the transaction boxes\n", "var txnWidth = 175;\n", "var txnHeight = 65;\n", "var txnPadding = 15;\n", "var colors = ['#0099CC', '#FF6666'];\n", "var tableHeaderHeight = 20;\n", "\n", "\n", "// Render the svg canvas\n", "var makeViewer = function() {\n", " $(\"#chart-\"+chartNum).html('');\n", "\n", " // Have width be relative to the width of the IPython output subarea width\n", " var W = $('.output_subarea').width() - 20;\n", " var canvasProportion = 0.7;\n", " var canvasWidth = canvasProportion * W;\n", " var canvasHeight = txnPadding + numThreads * (txnHeight + txnPadding);\n", "\n", " // Set the var table width appropriately\n", " $('#vals-'+chartNum).width((1 - canvasProportion)*W + 'px');\n", "\n", " // Top spacing (hackey)\n", " var topMargin = tableHeaderHeight + txnHeight;\n", " $(\"#top-spacer-\"+chartNum).height(topMargin);\n", " $(\"#chart-\"+chartNum).css(\"margin-top\", 0);\n", "\n", " // Make the svg canvas\n", " var svg = d3.select(\"#chart-\"+chartNum)\n", " .append('svg')\n", " .attr({\n", " 'width': canvasWidth,\n", " 'height': canvasHeight,\n", " 'x': topMargin\n", " })\n", " .style('border', '1px solid black');\n", "\n", " // Populate the timeline with transaction boxes\n", " makeTxns(svg, canvasWidth, canvasHeight);\n", "}\n", "\n", "// Lay out the transition boxes- g with rect + text\n", "// NOTE that the first txn in txnLog is a placeholder (for initial vals)!\n", "var makeTxns = function(svg, canvasWidth, canvasHeight) {\n", " \n", " // Make a group for the whole timeline for sliding animation\n", " var timelineWidth = txnPadding + (txnLog.length - 1) * (txnWidth + txnPadding);\n", " var dT = -Math.max(timelineWidth - canvasWidth);\n", " var timeline = svg.append('g')\n", " .attr({\n", " 'id': 'timeline-g-' + chartNum,\n", " 'transform': 'translate(' + dT + ',0)',\n", " 'class': 'timeline'});\n", " \n", " // Make the timeline i.e. the TXN boxes\n", " var txns = timeline.selectAll('g.txn')\n", " .data(txnLog)\n", " .enter()\n", " .append('g')\n", " .attr({\n", " 'id': function(d,i) { return 'txn-' + chartNum + '-' + (i-1); },\n", " 'transform': function(d,i) {\n", " var x = txnPadding + (i-1) * (txnWidth + txnPadding);\n", " var y = txnPadding + d.thread * (txnHeight + txnPadding);\n", " return 'translate(' + x + ',' + y + ')'; },\n", " 'class': 'txn'})\n", " txns.append('rect')\n", " .attr({\n", " 'width': txnWidth,\n", " 'height': txnHeight,\n", " 'fill': function(d) { return colors[d.thread % colors.length]; },\n", " 'stroke': 'none'});\n", " txns.append('text')\n", " .attr({\n", " 'text-anchor': 'middle',\n", " 'dominant-baseline': 'middle', // NOTE: doesn't work in IE?\n", " 'dx': 0.5*txnWidth,\n", " 'dy': 0.5*txnHeight,\n", " 'font-size': \"14\",\n", " 'fill': 'white'})\n", " .text(function(d) { return d.operation; });\n", " \n", " // Initialize the state to that of the last txn\n", " var t = txnLog.length - 1;\n", " state = txnLog[t].state;\n", "\n", " // Make the slider and state table\n", " makeTable();\n", " makeLog(t);\n", " makeSlider(svg, timeline, timelineWidth, canvasWidth, canvasHeight);\n", "}\n", "\n", "var makeSlider = function(svg, timeline, timelineWidth, canvasWidth, canvasHeight) {\n", " var slider = $(\"#slider-\"+chartNum);\n", " var line = svg.append('line')\n", " .attr({\n", " 'class': 'slider-bar',\n", " 'x1': 0,\n", " 'x2': 0,\n", " 'y1': 0,\n", " 'y2': canvasHeight,\n", " 'stroke': '#393D3D',\n", " 'stroke-dasharray': '2,2',\n", " 'opacity': 0.5});\n", " slider.width(canvasWidth);\n", " slider.slider();\n", " slider.slider('option', 'value', slider.slider('option', 'max'));\n", " slider.off(\"slide\");\n", " slider.on(\"slide\", function(e,ui) {\n", " var p = ui.value / 100.0;\n", " var w = p * canvasWidth;\n", "\n", " // move the slider bar\n", " line.attr('transform', 'translate(' + w + ',0)');\n", "\n", " // move the timeline\n", " var dT = -p * Math.max(0, timelineWidth - canvasWidth);\n", " timeline.attr('transform', 'translate(' + dT + ',0)');\n", "\n", " // Find the index of the last txn that should be active\n", " var t = 0;\n", " while (w > t*(txnPadding+txnWidth) + txnPadding + 0.5*txnWidth + dT) {\n", " t += 1;\n", " }\n", " t -= 1;\n", "\n", " // show / hide the txns\n", " for (var tt=0; tt < txnLog.length; tt++) {\n", " if (tt <= t) {\n", " $(\"#txn-\" + chartNum + '-' + tt).css('opacity', 1.0);\n", " } else {\n", " $(\"#txn-\" + chartNum + '-' + tt).css('opacity', 0.3);\n", " }\n", " }\n", "\n", " // Set the state & re-render the values table appropriately\n", " if (t >= -1) {\n", " state = txnLog[t+1].state;\n", " }\n", " makeTable();\n", " makeLog(t+1);\n", " });\n", "}\n", "\n", "var makeTable = function() {\n", " \n", " // Make the header row- var names\n", " var html = '';\n", " for (var v in state) {\n", " if (state.hasOwnProperty(v)) {\n", " html += '' + v + '';\n", " }\n", " }\n", " html += '';\n", "\n", " // Make the local / thread rows\n", " for (var r=0; r < numThreads + 1; r++) {\n", " html += '';\n", " if (r > 0) {\n", " html += 'Thread ' + r + '';\n", " } else {\n", " html += 'Main';\n", " }\n", " for (var v in state) {\n", " if (state.hasOwnProperty(v)) {\n", " html += '' + state[v][r] + '';\n", " }\n", " }\n", " html += '';\n", " }\n", " $(\"#vals-\"+chartNum).html(html);\n", "}\n", "\n", "var makeLog = function(t) {\n", " html = \"\");\n", "}\n", "});\n", "});\n", "});\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "#from txn_viewer_v2 import TransactionManager # python 2인 경우\n", "from txn_viewer_v3 import TransactionManager # python 3인 경우\n", "\n", "# 초기값과 함게 몇 개의 스레드로 TransactionManager 객체를 생성하였다.\n", "tm = TransactionManager(n_threads=3, initial_main_vals={'A':50})\n", "\n", "a0 = tm.read(0, 'A')\n", "\n", "tm.write(1, 'A', 65)\n", "\n", "tm.write(0, 'A', 45)\n", "\n", "tm.write(2, 'A', 75)\n", "\n", "tm.display(chart_num=1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 문제 3: 고전적인 이상현상들의 예를 만들어 보자\n", "\n", "은행 계좌 한 두개를 사용하는 예제를 만들어도 되고 창의력을 발휘하여 재미있는 케이스를 만들어도 된다. 자신이 만든 이상현상의 예를 같이 살펴보자." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.15" } }, "nbformat": 4, "nbformat_minor": 2 }