質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

0回答

798閲覧

処理の軽量化について

holy_cow

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/08/26 05:57

編集2021/08/26 10:59

はじめに

こんにちは。いわゆるパラドゲーというものをご存知でしょうか。今回はその中でもVictoria 2の内部処理を想像して参考にしながら、自分のシステムを作り上げてみました。しかし、一番最初のテストの段階で既に処理が重すぎます。これの改善方法に知恵をお貸しいただけますと幸いです。

システムを簡潔に説明

Victoria 2をご存知でしたら想像に容易いのですが、知らない前提で説明いたします。
まず、プレイヤーが操作するものは国家です。国家には人口がおり、様々な職業や人種に分かれています。その人口が株式投資したり、会社を興したり、経済活動をすることで自国経済が動きます。プレイヤーが国家として市場に介入することはあれど、直接手を下すということはありません。そんなものを表現したいと思っています。

コード

C#

1using System; 2using System.IO; 3using System.Collections.Generic; 4using Newtonsoft.Json; 5 6namespace ConsoleApp2 7{ 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 var sw = new System.Diagnostics.Stopwatch(); 13 sw.Start(); 14 int chanceOfPopExcution = 1; 15 int chanceOfCompanyExcution = 1; 16 var pop = new Pop(chanceOfPopExcution, chanceOfCompanyExcution); 17 var company = new Company(); 18 Console.WriteLine(pop.popItems.Count); 19 Console.WriteLine(company.companyItems.Count); 20 pop.action(); 21 sw.Stop(); 22 Console.WriteLine("■処理Aにかかった時間"); 23 TimeSpan ts = sw.Elapsed; 24 Console.WriteLine($" {ts}"); 25 Console.WriteLine($" {ts.Hours}時間 {ts.Minutes}分 {ts.Seconds}秒 {ts.Milliseconds}ミリ秒"); 26 Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒"); 27 } 28 } 29 30 class Goods 31 { 32 public double life = 0.2; 33 public double everyday = 0.4; 34 public double luxury = 1.1; 35 } 36 37 public class Company 38 { 39 public List<CompanyItem> companyItems; 40 41 public Company() 42 { 43 using (var sr = new StreamReader(@"company.json", System.Text.Encoding.UTF8)) 44 { 45 var jsonData = sr.ReadToEnd(); 46 companyItems = JsonConvert.DeserializeObject<List<CompanyItem>>(jsonData); 47 } 48 } 49 public class CompanyItem 50 { 51 public int code { get; set; } 52 public double capital { get; set; } 53 public double asset { get; set; } 54 public double revenue { get; set; } 55 public double issued { get; set; } 56 public double apprprt_price { get; set; } 57 public double share_price { get; set; } 58 } 59 } 60 61 public class Pop 62 { 63 public List<PopItem> popItems; 64 public int chanceOfPopExcution; 65 public int chanceOfCompanyExcution; 66 public Pop(int _chanceOfPopExcution, int _chanceOfCompanyExcution) 67 { 68 chanceOfPopExcution = _chanceOfPopExcution; 69 chanceOfCompanyExcution = _chanceOfCompanyExcution; 70 using (var sr = new StreamReader(@"pop.json", System.Text.Encoding.UTF8)) 71 { 72 var jsonData = sr.ReadToEnd(); 73 popItems = JsonConvert.DeserializeObject<List<PopItem>>(jsonData); 74 } 75 } 76 77 public void action() 78 { 79 for (int i = 0; i < popItems.Count; i++) 80 { 81 var ob = new ChanceOfExcution(); 82 if (ob.calc(chanceOfPopExcution)) 83 { 84 Dictionary<string,double> consumption = consume(popItems[i]); 85 popItems[i].money = consumption["money"]; 86 if (consumption["fulfilled"] == 3) 87 { 88 invest(popItems[i]); 89 } 90 } 91 } 92 return; 93 } 94 95 public List<Dictionary<string, double>> invest(PopItem popItem) 96 { 97 var returnList = new List<Dictionary<string, double>>(); 98 var ob = new ChanceOfExcution(); 99 if (ob.calc(chanceOfCompanyExcution)) 100 { 101 var companyItems = new Company().companyItems; 102 103 double money = popItem.size * popItem.money; 104 105 for (int i = 0; i < companyItems.Count; i++) 106 { 107 108 var companyItem = companyItems[i]; 109 if (popItem.size * popItem.money * 0.8 > money) break; 110 if (companyItem.share_price == 0 || companyItem.apprprt_price / companyItem.share_price >= 1) 111 { 112 var obj = new Random(); 113 double rand = obj.Next(9, 12) / 10; 114 double investingPrice; 115 if (companyItem.share_price == 0) 116 { 117 investingPrice = 0.5 * Math.Round(rand, 1, MidpointRounding.AwayFromZero); 118 } 119 else 120 { 121 investingPrice = 0.5 * Math.Round(companyItem.share_price * rand, 1, MidpointRounding.AwayFromZero); 122 } 123 if (popItem.money / 10 > investingPrice) 124 { 125 double rand2 = obj.Next(5, 15) / 10; 126 double investingVolume = Math.Floor(money / 100 * rand2 / investingPrice); 127 var dic = new Dictionary<string, double>() { { "pop_code", popItem.code }, { "company_code", companyItem.code }, { "price", investingPrice }, { "volume", investingVolume } }; 128 returnList.Add(dic); 129 } 130 } 131 } 132 } 133 return returnList; 134 } 135 136 public Dictionary<string, double> consume(PopItem pop_item) 137 { 138 var goods = new Goods(); 139 double money = pop_item.money; 140 double multiplyer = (100 / chanceOfPopExcution); 141 if (money - goods.life * multiplyer < 0) { 142 return new Dictionary<string, double>(){ {"fulfilled",0},{"money",money}}; 143 } 144 else if(money - (goods.life + goods.everyday) * multiplyer < 0) 145 { 146 return new Dictionary<string, double>() { { "fulfilled", 1 }, { "money", money - goods.life } }; 147 } 148 else if(money - (goods.life + goods.everyday + goods.luxury) * multiplyer < 0) 149 { 150 return new Dictionary<string, double>() { { "fulfilled", 2 }, { "money", money - (goods.life + goods.everyday) * multiplyer } }; 151 } 152 else 153 { 154 return new Dictionary<string, double>() { { "fulfilled", 3 }, { "money", money - (goods.life + goods.everyday + goods.luxury) * multiplyer } }; 155 } 156 } 157 158 public class PopItem 159 { 160 public int code { get; set; } 161 public int size { get; set; } 162 public double money { get; set; } 163 public List<Dictionary<string,double>> share { get; set; } 164 } 165 } 166 167 public class ChanceOfExcution 168 { 169 public bool calc(int chance) 170 { 171 var ob = new Random(); 172 int rand = ob.Next(1, 10000); 173 int num = chance * 100; 174 return num >= rand; 175 } 176 } 177} 178

さいごに

このテストはpythonで記述しましたが、最終的にはunityで作りたいのでC#でやり直します。ですが、本質的に動作が重すぎる点は言語のせいではないと思いますので、この時点で何かアドバイスをいただきたいと思い、質問させていただきました。

追記

pop.jsonは100,000件のデータを、company.jsonは500件のデータを持っています。これら合計して50,000,000件計算させるのは心が痛むので、確率でPopとCompanyが動くようにしました。どちらも1%の確率で処理させ、合計処理を5000件に抑えたのですが、それでも処理に1秒くらいかかってしまいます。
本番環境では、これよりもっと複雑な計算も行いますし、PopもCompanyも一桁多いくらいな想定です。今のままでは不可能ですが、前述のゲーム、Victoria 2ではこの状況に非常によく似た問題の対処が行われています。全く想像つきません。一緒に考えてもらえませんか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mather

2021/08/26 06:04

全体の処理時間だけを測ってもボトルネックは見つからないので、ご自身で当たりをつけて気になる部分の時間を計測してみてください。
Zuishin

2021/08/26 06:05

Python と C# ではプログラムの組み方も変わってくるので、作り直すのであれば、今最適化したとしても意味ないと思いますが。 特に Unity であればコルーチンのような概念も入ってきます。
退会済みユーザー

退会済みユーザー

2021/08/26 06:34 編集

> 本質的に動作が重すぎる点は言語のせいではないと思います 言語が変われば速度も当然変わりますが。 (スクリプト言語、JITコンパイル言語、C++だとかなりの速度差がある) ただ、CPU以外の部分がボトルネックになっているならあまり関係ないので、まずmatherさんの言うように計測して遅くなっている箇所と原因を特定してください。
Zuishin

2021/08/26 07:17 編集

ざっと見たところ再帰はないし、ループは action と invest 中にそれぞれ一つだけで、invest は action の中のループから呼び出されているので、ロジックの中でボトルネックになるとすれば invest 中のループでしょう。 しかし中で特に重い処理をしているわけでもないので、companies と pops の数が常識外れに多いのでなければ、C# に移植することで問題は解消する可能性もあります。
Zuishin

2021/08/26 11:34 編集

8 から 9 桁回のループで 2 秒が目安です。 結局 50000000 回ループしているのでそのくらいの時間はかかると思います。 1% の確率で処理させるのであれば、本来のループ回数の 1% の数だけ乱数を発生させ、それを添え字に処理を行えば良いと思います。
holy_cow

2021/08/26 12:00

Zuishinさん、なるほど、思いつきませんでした! 確かに文字通り99%無駄なループが発生していました。こういうミスを直しつつも、最終的にはデータを縮小する方針になりそうです。ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問