AVT-C878 というキャプチャボードが認識してくれない話
ついに買いました。Splatoon2に向けて。
巷で “最強” とも称されるキャプチャボード
随分と物騒な噂ですが この程、Nintendo Switchをつなげて録画をしようとこんなものを購入しました。
AVerMedia Live Gamer Portable 2 AVT-C878 ゲームの録画・ライブ配信用キャプチャーデバイス DV422
- 出版社/メーカー: AVERMEDIA
- 発売日: 2016/11/09
- メディア: Personal Computers
- この商品を含むブログを見る
こちら。USBでつないで、1080p/60fpsで録画ができるという素晴らしいもの。
という謳い文句を 鵜呑みにして 買いました。
前から何度も店に足を運んではいろんなキャプチャボードを見てきましたが、値段的にも扱い方的にもこれがいいのかなと思って購入しました。
ガチなボードだとパソコンを起動しないといけないという手間もありますしね、これがいいかなと。
何度も言います。 これがいいかな、と思って。
思い込みで買うのは本当に怖いものですね。
人生の99%は思い込み―――支配された人生から脱却するための心理学
- 作者: 鈴木敏昭
- 出版社/メーカー: ダイヤモンド社
- 発売日: 2015/05/29
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
買ってつなげて初めて分かるもの
PC録画の推奨環境が 「Core i5-3xxx 以上 / NVIDIA GeForce GTX 650同等以上」 とあるので、結構なスペックが要求されるようです。
私が持っているPCの中ではメイン機だけが使えそう。
OS: Windows10
CPU: Core i7-6700
メモリ: 16GB
グラボ: NVIDIA GTX 1050
使えそうというか、これ絶対動くでしょ、って感じで甘く見てました。
……。
認識しない 。
PCとUSBでつなぐと、電源が入る。HDMIパススルーが機能して、普通にゲームも遊べる。
しかし、PC側にはなんの反応もない。いや、実際には少しだけ認識したけど、認識できないデバイスと言われ、ドライバにも黄色い三角マーク。
仕方なくドライバを削除して再起動。とりあえず標準ドライバを使うとWebカメラとして認識するみたいなので、それでやってみようと試みる。
が、何分経っても青点滅(準備中)が消えない。何度抜き差ししてもだめ。全く認識しない。
死亡フラグが立ちました! (宝島社文庫) (宝島社文庫 C な 5-1)
- 作者: 七尾与史
- 出版社/メーカー: 宝島社
- 発売日: 2010/07/06
- メディア: 文庫
- 購入: 4人 クリック: 532回
- この商品を含むブログ (44件) を見る
Ubuntuならどうか
サブ機(サーバー)のUbuntuにつなげてみて、Webカメラとして使えたら使おうと考えた。
グラボが載っていないので、もし認識したら安めのものを買ってきてつけようかとも考えた。
しかし、全く同じ状態が続く。青点滅が消えない。
挿した瞬間、HDDアクセスを示すLEDランプが一瞬光るので繋がった認識はしてるんだろうけど、そこから先動いてるように見えない。
OBSとかも全く反応してくれない。
カードリーダも使えない
AVT-C878はカードリーダーモードも備えていて、普通にmicroSDの中身を読み書きできるそう。
なのに それも動いてくれない 。やっぱり青点滅が消えない。
完全にUSBでPCとやり取りができていない。AVT-C787側も初期化が終わらないってことは、完全にハンドシェイクが切れてる。万事休す。
無理やりFWアップデート走らせたせい?その前から現象はあるけど…
ファームウェアが古いせいなのかなとか思って、microSDにデータをダウンロードして無理やりアップデート。
マニュアルにはカードリーダモードで転送するよう書いてあったけど、前述の通り使えないので、普通に別のカードリーダで転送。
入れて起動すると自動的にアップデートが始まって、 ゆっくり青く点滅 するらしい。が、実際にやってみるとなぜか 素早く青く点滅 していた。
アップデートが終わると自動でランプが消灯すると書いてあって、実際しばらくしたら消えたので、たぶんアップデートできてるはず。
実際バージョン情報見るには、後述のソフトがAVT-C878を認識しないといけないから、結局どうなったのかわからないんだけど…。
- アーティスト: クリフォード・ジョーダンClifford Jordan
- 出版社/メーカー: THINK! REOCRDS
- 発売日: 2017/07/05
- メディア: CD
- この商品を含むブログを見る
RECentral すら起動しない
連携ソフトというか、無料で配布されているキャプチャソフト兼コンフィグレーションソフトの RECentral なるものがあるのですが。
これ、起動すると5秒もしないうちに落ちる。
ウィンドウは出てくるけど、全く何も使えない。
それどころかボードを認識している様子すらない(Windowsが認識してないから当たり前か…)
調べてみると確かに、同じような現象に陥っている人はいるみたい。再インストールすれば治る人もいるけど、私みたいに全く治らない人もいそう。
単体録画は正常
これだけPC録画がボロボロなのに、単体録画はしれっと何事もなかったかのようにできている。
空のmicroSDを挿して、PCのUSBから電源だけ拝借する。MOVなので画質は粗めだけど、解像度はちゃんと1080p出てる。
ハードエンコードなので圧縮とか高度なことはしてくれないのですぐ容量なくなってしまうけど、とりあえず当面は使えるレベル。
とはいえもともとPC録画を目的に買ったから本末転倒って感じがする。。。
結局
しばらく単体モードでやりますが、そのうちお金に余裕ができたら別のボード買うかもね…。うーん辛い。
安全・サイン8 熱中飴 塩辛すっぱいレモン味 1kg(約200粒入り) CN3007-L
- 出版社/メーカー: つくし工房
- メディア: その他
- この商品を含むブログを見る
お兄ちゃん!そこは MemoryStream の出番だよ!
タイトルは釣りです(お約束)
MemoryStream のススメ
みなさん、 System.IO.MemoryStream
使っていますか。私はよく使いますよ。
MemoryStream Class (System.IO) | Microsoft Docs
リアクティブプログラミングだったり、Java の Stream API だったり、いろんな Stream がありますが、今回はC#の MemoryStream
に注目してみます。
MemoryStream のイロハ
そもそもC#には Stream
クラスがあり、 MemoryStream
はその派生クラスです。同じような派生クラスには FileStream
や CryptoStream
があります。
似て非なるものですが、これらは共通して データを順次読み出したり、順次格納したりできる という特徴を持っています。
たとえば FileStream
は、ディスク上のファイルを読み書きするクラスです。ファイルを開くと FileStream
にはそのファイルサイズと カーソル位置 が保持されます。
カーソル位置は Stream
のデータを操作する位置 を表します。これを使うと、例えばファイルの80バイト目から60バイト分読み出したい、といった場合に、カーソル位置を80バイト目に移動させ、そこから60バイト分読み出すことができます(同時にカーソルも60バイト動くため、次に60バイトを読み出すと140バイト目から60バイトを読み出します)。
これは、次のように書くことができます。
// ファイル名 を元に FileStream を作成 var stream = new FileStream("C:/hoge.txt", FileMode.Open); // 80バイト目から60バイト読み出す var puts = new byte[60]; stream.Position = 80; stream.Read(puts, 0, 60);
同様に MemoryStream
も、ある byte[]
のサイズ(配列の長さ)とカーソル位置が保持されます。
そして、例えばある byte[]
の80バイト目から60バイト分読み出したい、といった場合に、カーソル位置を80バイト目に移動させ、そこから60バイト分読み出すことができます。
これは、次のように書くことができます。
var array = new byte[300]; // --- ここに本来はデータの操作が入る --- // // array を元に MemoryStream を作成 var stream = new MemoryStream(array); // 80バイト目から60バイト読み出す var puts = new byte[60]; stream.Position = 80; stream.Read(puts, 0, 60);
なお、以下の配列へのアクセスをするコードで、同様の puts
を得られます。
var array = new byte[300]; // --- ここに本来はデータの操作が入る --- // // 80バイト目から60バイト読み出す var puts = new byte[60]; for (int i = 0; i < 60; i++) puts[i] = array[80 + i];
え、じゃあ何に使うん 。
MemoryStream は byte[]
へのアクセスを簡単にします。本当に?
ひどい夢を見ました。すべての byte[]
配列へのアクセスを、 MemoryStream
を通じて行うようにするという、お達しが出たのです。まったく、とんだ災難です。このプロダクトは文字列や数値としては扱えないデータが山ほどあり(画像や音声、もしかしたら地球外生命体のDNAの解析結果かもしれない)、それらはすべて byte[]
で表すことになっています。だから、それら全てのアクセスを、 MemoryStream
に置き換えなければなりません。たった1要素の読み込みでさえ、長ったらしく2,3行を書き連ねなければならないのです。
実際にそんなことがあるはずはありません。安心してください。 ところで次の例を見てくれ、こいつをどう思う?
// AESで暗号化するためのオブジェクトを初期化 var aes = new AesManaged(); aes.GenerateIV(); aes.GenerateKey(); // MemoryStreamを作成 var memStream = new MemoryStream(); // CryptoStreamを作成 var cryStream = new CryptoStream(memStream, aes.CreateEncryptor, CryptoStreamMode.Write); // CryptoStreamに書き込み cryStream.Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5); // MemoryStreamから読み出し var read = byte[3]; memStream.Position = 1; memStream.Read(read, 0, 3);
AesManaged Class (System.Security.Cryptography) | Microsoft Docs
CryptoStream Class (System.Security.Cryptography) | Microsoft Docs
ちょっと難解ですが、 ある MemoryStream
を参照する CryptoStream
にデータを書き込むと、 MemoryStream
に暗号化されたデータが書き込まれる コードです。
上記の例では read
に暗号化されたデータの一部が代入されることになります。
さてこれをちょっとだけ改変しましょう。
// AESで暗号化するためのオブジェクトを初期化 var aes = new AesManaged(); aes.GenerateIV(); aes.GenerateKey(); // FileStreamを作成 var filStream = new FileStream("C:/hoge.enc", FileMode.Create); // CryptoStreamを作成 var cryStream = new CryptoStream(filStream , aes.CreateEncryptor, CryptoStreamMode.Write); // CryptoStreamに書き込み cryStream.Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
だいたい想像がつくと思いますが、これは ある FileStream
を参照する CryptoStream
にデータを書き込むと、 FileStream
に暗号化されたデータが書き込まれる(暗号化されたデータがファイルに書き込まれる) コードです。
驚くべきことに、このコードを先ほどのコードと比べると、 MemoryStream
を FileStream
にすり替えただけなのです。
MemoryStream は世界を救う
つまり、 MemoryStream
は、 byte[]
を FileStream
、すなわち 変数操作とファイル操作と同等に扱えるようにするクラス ということなのです。
C# では、とくにデータの変換系の処理を Stream
で行うような風潮があるように見えます。
例えば暗号化や、巨大なバイナリファイルの符号化など。JSONのシリアライズにも Stream
クラスを引数に受けるメソッドを用います。
こうすることで、対象がファイルでもメモリでも、同じ操作でデータを扱えるという素晴らしい恩恵を享受することができます。
単体テストもコードの再利用もどんとこい、な機能ですね。
さいごに
素人が生意気にすみませんでした 。ちょっと魔がさして書き始めたら収拾がつかなくなってしまいました。申し訳ありません。反省はしていません。
この間 JSON をC#のクラスにシリアライズしたりデシリアライズするときに MemoryStream
を使う機会があったのですが、正直な話
なんでクラスで管理できる情報量をわざわざ MemoryStream
で書く必要があるのか、変数でいいのではないか
と思いながらバリバリ書いてたんですね。
そしてふと、思いついたんですよね。JSON ってファイルの可能性があるよなぁ、と。
自分の中ではとても面白い発見だったので、ついつい長ったらしく書いてしまいました。本当に申し訳ありませんでした。
最後まで見てくださって本当にありがとうございました。
P.S.
本来書きたかったネタもとりあえず置いておきます。 MemoryStream
の Read
メソッドが超絶使いにくい件について。
public static class MemoryStreamExtention { public static byte[] ReadAllBytes(this System.IO.MemoryStream target) { byte[] ret = new byte[target.Length]; target.Position = 0; target.Read(ret, 0, (int)target.Length); return ret; } }
.NET core コンソールアプリで文字化けするときの対処法
Main
メソッドの一番頭にこれを書く。
Console.OutputEncoding = Console.OutputEncoding;
何をしているのか
.NET core コンソールアプリでは、規定で Console.OutputEncoding
に System.Text.UTF8Encoding
のインスタンスが入っています。
しかし、コンソール側(Windowsでデバッグした場合は規定でコマンドプロンプト)がこれをまだ検知していない状態のため、UTF-8でないコードページで表示をしています。
そのため、一度プロパティのsetterを通す必要があります。
…という推測を立てただけです。すみません。
Ubuntuのtaskselを使って、ラクしてKVM環境を作る
Linuxで楽しよう。Linuxを楽しもう。(名言っぽく言ってみるだけ)
ふと tasksel
でxubuntu desktopを選ぼうとすると、そこにそれらしき項目があったので、使ってみた。その時のメモ。
基本、シェルはbashでroot権限で行きます。 sudo
はつけないので、 su
したくない方は sudo
をつけて実行してください。
PCが仮想化に対応しているか確認する
KVMは完全仮想化をCPUの仮想化技術で実現しているようなので、次のコマンドで確認する。
# egrep -c '(vmx|svm)' /proc/cpuinfo
出力が1以上なら仮想化できます。
パッケージをインストールする
とりあえずKVM環境を動かすためのライブラリ群を入れます。次のコマンドを打ちます。
# tasksel
GUIっぽい画面が出てくるので、一覧から「Virtual Machine Host」に スペースキー でチェックを入れ、 エンターキー で続行します。
あとは待つだけ。これが終わると、仮想化に必要なものがほとんど入ります。
ただし、GUIで設定できる「virt-manager」はあいにく入れてくれないので、これだけは手動で入れます。
# apt install virt-manager
これがあれば、Virtual BoxみたいにGUIで簡単に操作ができるようになります。
ネットワークインターフェイス(NIC)をブリッジする
なんか、皆さんこぞってブリッジしているので、ブリッジしたほうが幸せなのかな?と半信半疑でブリッジしました。
一応パッケージをチェック。
# apt list | grep bridge-utils
[インストール済み] と末尾に表示されていなければ、インストールします。
# apt install bridge-utils
次に、ブリッジするよう /etc/network/interfaces
を編集
Ubuntuは最近、規定のNICのインターフェイス名が環境によって変わるようになったので、適宜読み替えてください。
auto enp0sXXXX iface enp0sXXXX inet manual auto br0 iface br0 inet static address 192.168.XXX.XXX network 192.168.XXX.0 netmask 255.255.255.0 gateway 192.168.XXX.XXX dns-nameservers XXX.XXX.XXX.XXX bridge-ports enp0sXXXX bridge-stp off
元あった規定NICのインターフェイスの設定はすべてコメントアウトか削除かしておきます。その設定を、br0側にすべて書きます。
この後、再起動して ifconfig
でbr0側にIPアドレスなどが定義されていることを確認。
参考サイト
aptでインストールした残骸を確認する
完璧に備忘録ですが。
パッケージの一覧を取得する
# apt list
パッケージの一覧が表示されます。インストール済みかそうでないかにかかわらず、データベースに登録してあるパッケージはすべて出ます。
たぶんこの一覧の中からパッケージの情報を取り出すんだと思います。
設定が残る
上記のコマンドで表示した一覧で、末尾に次のような表示がされることがあります。
この「設定が残存」があると、再インストール時に --update
フラグとかが自動でつけられたりして、クリーンインストールはしないようです。
設定を消す
# apt purge <パッケージ名> # apt remove --purge <パッケージ名>
どちらでもいいみたい、
Ubuntu16.10でIPを固定しDNSを指定するのに、2時間かけました。
Ubuntuのことをあまり知らずに挑むからダメなんですよね。
とはいえ、IPを固定するくらいはいくらシステムの根幹に近いカスタマイズとはいえ、もうちょっと簡単でもいいと思うんですよ…
変更した箇所
- /etc/network/interfaces
- /etc/hosts
- /etc/NetworkManager/NetworkManager.conf
- /etc/resolvconf/resolv.conf.d/tail
いちおうこれらは確実に変更してあります。
ほかにも触ったところあったかもしれないけど、毎回Ubuntuマシン触るときに悩まされる種でもありイライラしていたので覚えていない…。これだからブログ向いてないんですよね。知ってます。
※なお、これから同じような設定をされる方は、ほかの方の記事やしっかりとした情報を一通り見てから実際に設定されることを強くお勧めします。
/etc/network/interfaces
auto lo ifacw lo inet static
が初期設定。これを次のように変更します。
auto enpX iface enpX inet static address <固定するアドレス XXX.XXX.XXX.XXX> netmask <サブネットマスク XXX.XXX.XXX.XXX> gateway <デフォルトゲートウェイ XXX.XXX.XXX.XXX> dns-nameservers <DNSサーバ XXX.XXX.XXX.XXX>
enpX
はNICのアドレスのようなもので、 ifconfig
コマンドで確認ができます。
lo
から enpX
に変更するので、 ifconfig
を走らせたときに lo
と同じような位置に出てくるやつがそれです。
なおDNSサーバプライマリとセカンダリをスペースで区切って指定できるようです。
/etc/hosts
変更する意味があるかと言われれば、もしかしたらないかもしれないですが、一応変更します。
127.0.0.1 localhost 127.0.1.1 <コンピュータ名> # The following lines are disirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback ・ ・ ・
最後のほうは面倒なので端折りました。
ここに出てくる 127.0.1.1
を変更します。
127.0.0.1 localhost <固定するアドレス> <コンピュータ名> # The following lines are disirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback ・ ・ ・
/etc/NetworkManager/NetworkManager.conf
悪党を倒しに行きます(?)
[main] plugins=ifupdown,keyfile,ofono dns=dnsmasq [ifupdown] managed=false
これを、以下のように直します。
[main] plugins=ifupdown,keyfile,ofono #dns=dnsmasq [ifupdown] managed=false
これで悪党は目覚めないことでしょう。きっと。
/etc/resolvconf/resolv.conf.d/tail
最後に強制的にDNSを変えます。もう最終手段です。
このファイルは、私の環境では入っていなかったため、自分で作りました。
そして以下のように記述します。
nameserver <DNSサーバ XXX.XXX.XXX.XXX (プライマリ)> nameserver <DNSサーバ XXX.XXX.XXX.XXX (セカンダリ)>
果たして /etc/network/interfaces に記述した dns-nameservers
に意味はあったのだろうか。
そして最後、 resolv.conf を生成します。
$ sudo resolvconf -u
再起動
最後に再起動すれば、IPアドレスは固定になり、DNSサーバも変わっているはず。
時間がかかった。
結局、表題の通りすべての帳尻合わせするため 2時間 以上はかけました。はい。
IPアドレスを固定するために /etc/interfaces を書き換えている方がたくさんいたのですが、それだけだとなぜかうまくいかなくて。
試行錯誤を重ねてやっと固定された感じです。つらい。
やっぱりここらへんはCentOSのほうが楽なんでしょうかね。。。
StringBuilderをstringと同じだけ作ると、どれほど遅いのか。
この間、以下のようなコードを見かけました。
StringBuilder strSql = new StringBuilder(); strSql.Append(@"SELECT * FROM ... WHERE ..."); // SQLは長いので省略。 this.ExecuteNonQuery(strSql.ToString());
フォームのメソッドに書かれていたのですが、フォーム自体がユーザコントロールになっていて、データベース接続の機能をすでに実装しているんですね。
なので、それにSQLを投げれば完了というすごくシンプルなものなのですが。
StringBuilderにする必要あったのかなって。
StringBuilderを必要とする理由
StringBuilder
は、 string
型が演算で毎回新しいインスタンスを生成したり破棄したりするのに対して、最初のインスタンスを使いまわすために使う、というものだと思います。
具体的には次のコード。
string s = ""; s = s + "a"; s = s + "b"; s = s + "c";
上記のコードでは、最終的に変数 s
に入るのは "abc"
という文字列ですが、その文字列を得るまでにインスタンスを生成する回数は7回です。
それに対し、
StringBuilder s = new StringBuilder(); s.Append("a"); s.Append("b"); s.Append("c");
上記のコードでも同様に、最終的に変数 s
に入るのは "abc"
という文字列ですが、インスタンスの生成は4回で済みます。
インスタンスの生成、という観点からみると、 string
型より StringBuilder
型のほうが同じインスタンスを使いまわすためオーバーヘッドが少ないと考えられます。
しかし。
最初のコードって、はじめに StringBuilder
型の変数を確保しているので、毎回インスタンスを生成していることになるんですよね。
これではstring型を直で触るのと変わらないのでは…。
ということで調べてみました。
検証コード
次の検証コードを用意しました。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { /// <summary> 出力用ダミー変数 </summary> static string d_out; /// <summary> /// メインエントリポイント /// </summary> static void Main(string[] args) { try { int count1; int count2; List<double> measuredList = new List<double>(); //------------------------------// // 入力 //------------------------------// do Console.WriteLine("1回の計測で確保を行う回数を指定してください..."); while (!int.TryParse(Console.ReadLine(), out count1)); do Console.WriteLine("計測を行う回数を指定してください..."); while (!int.TryParse(Console.ReadLine(), out count2)); //------------------------------// // 計測 string //------------------------------// measuredList.Clear(); Console.WriteLine("-------------------------------------------------------"); Console.WriteLine("stringクラスで計測します。"); GC.Collect(GC.MaxGeneration); for (int i = 0; i < count2; i++) { measuredList.Add(MeasureTime_String(count1)); Console.WriteLine((i + 1).ToString().PadLeft((int)Math.Log10(count2) + 1) + "回目 : " + measuredList[i]); } Console.WriteLine("平均 : " + measuredList.Average()); //------------------------------// // 計測 StringBuilder //------------------------------// measuredList.Clear(); Console.WriteLine("-------------------------------------------------------"); Console.WriteLine("StringBuilderクラスで計測します。"); GC.Collect(GC.MaxGeneration); for (int i = 0; i < count2; i++) { measuredList.Add(MeasureTime_StringBuilder(count1)); Console.WriteLine((i + 1).ToString().PadLeft((int)Math.Log10(count2) + 1) + "回目 : " + measuredList[i]); } Console.WriteLine("平均 : " + measuredList.Average()); //------------------------------// // 計測 StringBuilder + Append //------------------------------// measuredList.Clear(); Console.WriteLine("-------------------------------------------------------"); Console.WriteLine("StringBuilderクラス + Appendメソッドで計測します。"); GC.Collect(GC.MaxGeneration); for (int i = 0; i < count2; i++) { measuredList.Add(MeasureTime_StringBuilderAppend(count1)); Console.WriteLine((i + 1).ToString().PadLeft((int)Math.Log10(count2) + 1) + "回目 : " + measuredList[i]); } Console.WriteLine("平均 : " + measuredList.Average()); } finally { Console.WriteLine("何かキーを押してください..."); Console.ReadKey(); } } /// <summary> /// stringクラスを指定された回数確保し、その時間を計測します。 /// </summary> /// <param name="count">回数</param> /// <returns>時間(秒)</returns> static double MeasureTime_String(int count) { DateTime strT = DateTime.Now; for (int i = 0; i < count; i++) { string s = ""; s = s + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; Program.d_out = s.ToString(); } DateTime endT = DateTime.Now; return (endT - strT).TotalSeconds; } /// <summary> /// StringBuilderクラスを指定された回数確保し、その時間を計測します。 /// </summary> /// <param name="count">回数</param> /// <returns>時間(秒)</returns> static double MeasureTime_StringBuilder(int count) { DateTime strT = DateTime.Now; for (int i = 0; i < count; i++) { StringBuilder s = new StringBuilder("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); Program.d_out = s.ToString(); } DateTime endT = DateTime.Now; return (endT - strT).TotalSeconds; } /// <summary> /// StringBuilderクラスを指定された回数確保し、Appendメソッドで文字列を指定します。その時間を計測します。 /// </summary> /// <param name="count">回数</param> /// <returns>時間(秒)</returns> static double MeasureTime_StringBuilderAppend(int count) { DateTime strT = DateTime.Now; for (int i = 0; i < count; i++) { StringBuilder s = new StringBuilder(); s.Append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); Program.d_out = s.ToString(); } DateTime endT = DateTime.Now; return (endT - strT).TotalSeconds; } } }
汚いとか言わない。
実際にやってみた。
実際に動かしました。スペックは以下の通り。
- CPU: Atom Z3775 (1.46GHz 4core)
- メモリ: 2GB
やっぱり、string型のほうがオーバーヘッドは少ないみたいですね。
追記 2017/02/26 実験に使ったスペックを記述していなかったので追記。